Mixed example of Servant URL

Hello. I would like to know how to update the performLoginHandle to take the loginForm object from the request body, while also having a PostgresConnection argument.

type PostgresConnection = Database.HDBC.PostgreSQL.Connection

data LoginForm = LoginForm
  { username :: String
  , password :: String
  , nextUrl :: String
  } deriving (Eq, Show, Generic)
instance ToJSON LoginForm
instance FromJSON LoginForm

type PerformLoginRoute = "perform-login" :> ReqBody '[JSON] LoginForm :> Get '[HTMLLucid] (Html ()) 

performLoginHandle :: PostgresConnection -> Server PerformLoginRoute
performLoginHandle conn = "not_implemented"  -- redirect to success_page or error_page

pageserver :: PostgresConnection -> Application
pageserver conn = serve router (performLoginHandle conn)

because PerformLoginRoute takes a ReqBody, Server PerformLoginRoute is actually LoginForm -> Handler (Html ()), which means your server handler has type PostgresConnection -> LoginForm -> Handler (Html ()) meaning you can take the connection as the first argument and the login form as the second :slight_smile:

The type of the web application is determined by the API type, through a type family named Server . (Type families are just functions that take types as input and return types.) The Server type family will compute the right type that a bunch of request handlers should have just from the corresponding API type.

Did you see that? The types for your handlers changed to be just what we needed! In particular:

  • a Capture "something" a becomes an argument of type a (for position);
  • a QueryParam "something" a becomes an argument of type Maybe a (because an endpoint can technically be accessed without specifying any query string parameter, we decided to “force” handlers to be aware that the parameter might not always be there);
  • a ReqBody contentTypeList a becomes an argument of type a;
2 Likes