Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example for FormUrlEncoded endpoint #236

Closed
rubenmoor opened this issue Sep 24, 2015 · 10 comments
Closed

Example for FormUrlEncoded endpoint #236

rubenmoor opened this issue Sep 24, 2015 · 10 comments

Comments

@rubenmoor
Copy link
Contributor

Is there an example on how to implement a FormUrlEncoded endpoint in Servant?

I'm trying to build plain, old HTML forms (using digestive-functors and blaze) and want Servant to handle GET and POST. For digestive functors I need to build an Env m and I'm looking for a good starting point.

Atm I don't even understand what the consequences of the FormUrlEncoded-contenttype are, as in here:

type Api = "contract" :> "create" :> ReqBody '[FormUrlEncoded] ContractData :> Post '[HTML] Html
@fizruk
Copy link
Member

fizruk commented Sep 24, 2015

Have you looked at ToFormUrlEncoded/FromFormUrlEncoded classes in Servant.API.ContentTypes?

If you're making a server, you just need to implement instance FromFormUrlEncoded ContractData to be able to handle incoming form data.

@fizruk
Copy link
Member

fizruk commented Sep 24, 2015

Also documentation on FormUrlEncoded tells you that it uses application/x-www-form-urlencoded content type.

@alpmestan
Copy link
Contributor

Here's a minimal example of using FormUrlEncoded.

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative
import Data.Aeson
import Data.Monoid
import Servant

type API = "login" :> ReqBody '[FormUrlEncoded] User :> Post '[JSON] Login

data Login = LoggedIn | NotLoggedIn
  deriving (Eq, Show)

instance ToJSON Login where
  toJSON = toJSON . show

data User = User
  { email :: Text
  , password :: Text
  } deriving (Eq, Show)

instance FromFormUrlEncoded User where
  fromFormUrlEncoded inputs =
    User <$> lkp "email" <*> lkp "password"

    where lkp input_label = case lookup input_label inputs of
                 Nothing -> Left $ "label " <> input_label <> " not found"
                 Just v    -> Right v

server :: Server API
server usr =
  if email usr == "admin@admin.com" && password usr == "1234"
  then return LoggedIn
  else return NotLoggedIn

Now, as you can see, in the FromFormUrlEncoded instance I don't do any fancy validation here. inputs is a list of all inputs pairs (input_name, input_value), of type [(Text, Text)], which I'm pretty sure most validation libraries will happily let you work with. I however don't use any of them but would be glad to help you figure out how to wire those to this FromFormUrlEncoded class :)

@rubenmoor
Copy link
Contributor Author

Great, thanks! I'll be able to take it from here.

@alpmestan
Copy link
Contributor

Feel free to use this issue to ask questions, if you get stuck further down the road.

@jkarni
Copy link
Member

jkarni commented Sep 24, 2015

I think it'd be very useful to have an example of using digestive-functors with servant though. @rubenmoor if you end up doing that, please consider adding an example to servant-examples!

@rubenmoor
Copy link
Contributor Author

@jkarni will sure do!

@alpmestan
Copy link
Contributor

Can we consider this issue solved/closed?

@rubenmoor
Copy link
Contributor Author

Closed, in my opinion. I'll get back later with my solution and open questions regarding the combination of Servant with digestive-functors.

@alpmestan
Copy link
Contributor

Yeah, definitely. Just open an issue about this when you manage to make both play well together :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants