Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirections in Servant

What's the appropriate way to make a Servant handler respond with a redirection? I am working in a navigation REST app and I would like to respond to POST requests that create resources with a redirection to the corresponding GET resource list paths. So for instance POST /foos should redirect to GET /foos after creating a foo. I could not find a clear way to do that in the documentation.

like image 255
Jesuspc Avatar asked Oct 17 '17 11:10

Jesuspc


1 Answers

There is one simple (but slightly hacky) answer, and a lead for making the first option obsolete (EDIT: and a third, better option, actually).

The current typical solution for this is to simply use the fact that the Handler monad has a MonadError ServantErr instance, and that ServantErr is a very general "response type" that can indeed describe the HTTP response for an application error, but also a redirect or many other things really. So you can do something like throwError $ err301 { errHeaders = [("Location", "https://haskell.org/")] }. It's ugly because we hijack the "erroring out" bit for some successful workflow. But it works, and is a single line of code.

I have explored alternative approaches, that let you mix type-safe links with redirects to easily redirect to other endpoints/pages of your app. This is outdated now but could probably be made to work without toooo much trouble.

And upon seeing this question, I just now thought of a third option. Took a bit of time to experiment with it and looks like it works! You can see the code with an example of using it in this gist. Let me know if you have any question. We might want to add some of this to servant. Feel free to bring it up on the issue tracker if you think this is good enough. The gist of this approach is to define a custom PostRedirect that has the right shape (no response body, a Location header with a type of your choice, and parametrized by the status code that you want your redirect to use), and a little function that wraps the location appropriately before returning.

like image 145
Alp Mestanogullari Avatar answered Sep 22 '22 05:09

Alp Mestanogullari