Description
Hi everyone,
This has been discussed a bit offline but I thought I should open an issue and throw some code in here for discussion and potential inclusion in servant. The deal here is to offer a proper generic combinator for redirection.
One thing however is that we have some decent machinery for generating type safe links, which of course looks like a good basis to build the redirect combinator on.
For a servant-0.4 compatible solution, one could consider such an implementation:
class KnownMethod (c :: [*] -> * -> *) where
methodOf :: Proxy c -> Method
instance KnownMethod Delete where
methodOf _ = methodDelete
instance KnownMethod Get where
methodOf _ = methodGet
instance KnownMethod Patch where
methodOf _ = methodPatch
instance KnownMethod Post where
methodOf _ = methodPost
instance KnownMethod Put where
methodOf _ = methodPut
data Redirect (c :: [*] -> * -> *) lnk api
instance (KnownMethod c, IsElem lnk api, HasLink lnk)
=> HasServer (Redirect c lnk api) where
type ServerT (Redirect c lnk api) m
= m URI
route Proxy getLink req respond
| null (pathInfo req) && requestMethod req == methodOf pc = do
res <- runEitherT getLink
case res of
Left err -> respond . succeedWith $ responseServantErr err
Right lnk -> respond . succeedWith $
responseLBS seeOther303 [("Location", fromString ("/" ++ show lnk))] ""
| null (pathInfo req) && requestMethod req /= methodOf pc =
respond $ failWith WrongMethod
| otherwise = respond $ failWith NotFound
where pc = Proxy :: Proxy c
(complete usable code here)
The only thing I'm not happy about is that I hardcode the 303
status code. We could probably take an additional parameter of kind Natural
(type-level natural number) and only have the HasServer
instance when that number is a valid status code used for redirects.
Thoughts?
PS: I use the above combinator in a work project already and hence would be keen to eventually include such a combinator in servant itself since I would otherwise have to maintain that combinator independently and adapt it for any change to servant/servant-server.