Skip to content

Redirect combinator ?Β #117

Open
Open
@alpmestan

Description

@alpmestan

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions