使用servant处理常规表单帖子(application / x-www-form-urlencoded)

时间:2016-10-02 17:34:47

标签: forms haskell post servant

如何使用Servant处理常规表单POST?特别是,给出像

这样的HTML表单
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


<button type="button" id="myBtn">Load Data</button>
<div class="dictionary-stack"></div>

<form action="/check" method="post">
  Solution:
  <input name="code" type="text">
  <input type="submit">
</form>

如何将事物串在一起?

2 个答案:

答案 0 :(得分:4)

我只是想为最新版本的Servant添加答案,因为我必须谷歌各种各样的东西,以便组装一个完整的,工作版本的表单处理。

上述答案适用于早期版本的Servant,但在升级到Servant 0.9时,我无法使用表单。

我是这样做的。

首先,他们从自定义表单实现切换到http-api-data中的表单实现,因此您需要在您的cabal文件中:

一些-project.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

之后,您可以在终端中使用来自Servant的常规FormUrlEncoded ContentType:

type ContactApi = "contact" :> ReqBody '[FormUrlEncoded] ContactForm
                                   :> Post '[HTML] Html

几乎忘了:如何渲染

您可能还需要一个页面,显示您的表单?好吧,“name”属性必须与表单中的字段匹配(以下是我使用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"

答案 1 :(得分:3)

Servant通过数据类型FormUrlEncoded和类FromFormUrlEncoded(在Servant 0.9中重命名为data CheckResult = Correct | Wrong instance ToHtml CheckResult ... checkCode :: Text -> Handler CheckResult checkCode code = if code == "secret" then Correct else Wrong )支持此功能。

首先,我们为表单数据定义数据类型,并重写我们的处理程序以接受它。

FromForm

然后我们指定一个data CheckRequest = CheckRequest { code :: Text } checkCode :: CheckRequest -> Handler CheckResult checkCode (CheckRequest code) = if code == "secret" then Correct else Wrong 类型的POST主体。

application/x-www-form-urlencoded

现在所需要的只是让type API = "check" :> ReqBody '[FormUrlEncoded] CheckRequest :> Post '[HTML] CheckResult 成为CheckRequest的实例。

FromFormUrlEncoded