我只是想为最新版本的 Servant 添加一个答案,因为我必须在谷歌上搜索各种东西才能组装一个完整的、有效的表单处理版本。
上面的答案适用于早期版本的 Servant,但是在升级到 Servant 0.9 时,我在使用表单时遇到了困难。
这就是我的做法。
首先,他们从自定义 Form 实现切换到http-api-data中的实现,因此您需要在 cabal 文件中使用它:
一些项目.cabal
build-depends: base >= 4.7 && < 5
, aeson
, blaze-html
, http-api-data
接下来,您可以像上面一样声明一个表单,但您可以使用它GHC.Generics
来自动派生一个FromForm
实例:
{-# LANGUAGE DeriveGeneric #-}
module Html.Contact where
import GHC.Generics
import Servant
import Web.FormUrlEncoded (FromForm)
data ContactForm = ContactForm
{ cname :: !T.Text
, cemail :: !T.Text
, cmessage :: !T.Text
} deriving (Eq, Show, Generic)
instance FromForm ContactForm
之后,您可以FormUrlEncoded
在端点中使用来自 Servant 的常规 ContentType:
type ContactApi = "contact" :> ReqBody '[FormUrlEncoded] ContactForm
:> Post '[HTML] Html
差点忘了:如何渲染这个东西
您可能还需要一个页面,在哪里显示您的表单?好吧,“名称”属性必须与表单中的字段匹配(这是我的做法,使用Blaze
):
contactForm :: H.Html
contactForm = H.section ! A.id "contact" ! A.class_ "container contact-us u-full-width u-max-full-width" $
H.div ! A.class_ "row" $ do
H.div ! A.class_ "eight columns contact-us-form" $
H.form ! A.method "post" ! A.action "/contact" $ do
H.div ! A.class_ "row" $ do
H.div ! A.class_ "six columns" $
H.input ! A.class_ "u-full-width" ! A.type_ "text" ! A.name "cname" ! A.placeholder "Name" ! A.id "nameInput"
H.div ! A.class_ "six columns" $
H.input ! A.class_ "u-full-width" ! A.type_ "text" ! A.name "cemail" ! A.placeholder "Email" ! A.id "emailInput"
H.textarea ! A.class_ "u-full-width" ! A.name "cmessage" ! A.placeholder "Message" ! A.id "messageInput" $ ""
H.input ! A.class_ "button u-pull-right" ! A.type_ "submit" ! A.value "Send"