Happstack: веб-маршруты и данные форм

Итак, вчера я попытался использовать Happstack по-настоящему.

ОК, так что мой актуальный вопрос. Я получил это до сих пор:

data LambdaURL =
  URL_CSS   |
  URL_Input |
  URL_Output

instance PathInfo LambdaURL where
  toPathSegments url =
    case url of
      URL_CSS    -> ["Main.css"]
      URL_Input  -> ["Input.html"]
      URL_Output -> ["Output.html"]

  fromPathSegments =
    (segment "Main.css"    >> return URL_CSS   ) <|>
    (segment "Input.html"  >> return URL_Input ) <|>
    (segment "Output.html" >> return URL_Output)

route :: LambdaURL -> RouteT LambdaURL (ServerPartT IO) Response
route url =
  case url of
    URL_CSS    -> serveFile (asContentType "text/css") "Main.css"
    URL_Input  -> ok $ toResponse $ page_Input
    URL_Output -> ok $ toResponse $ page_Output

main = simpleHTTP nullConf $ implSite "www.example.com" "" (setDefault URL_Input $ mkSitePI (runRouteT route))

page_Input :: H.Html

page_Output :: H.Html

Так что это учебник по веб-маршрутам. Теперь я иду читать учебник по формам, и я понимаю, что для доступа к данным формы, вы должны быть в ServerPart монада, а не Html монада. В итоге я делаю что-то вроде

generate_page_Output :: ServerPart Response
generate_page_Output = do
  decodeBody (defaultBodyPolicy "." 0 65536 65536)
  expr <- look "expr"
  ok $ toResponse $ page_Output expr

page_Output :: String -> H.Html

Теперь я иду изменить route функция для вызова generate_page_Output скорее, чем page_Output, Предположительно так:

URL_Output -> generate_page_Output

Ну, что же вы знаете? Это не проверка типа. route живет в RouteT монада, пока я пытаюсь делать вещи в ServerPart монада. В конце концов я нахожу liftRouteT :: m a -> RouteT url m a, Кажется вероятным, а? Так что, если я изменю строку на

URL_Output -> liftRouteT generate_page_Output

теперь он компилируется. Самое интересное... теперь URL выходной страницы - HTTP 404. На данный момент я абсолютно не знаю, почему. Я просто еще не нашел правильный вызов функции.

Кто-нибудь знает, как это исправить?

1 ответ

Решение

Я понимаю, что для доступа к данным формы, вы должны быть в монаде ServerPart

Это не совсем верно. Чтобы получить доступ к данным формы, вы должны быть в любой монаде, которая является экземпляром HasRqData, ServerPart является базовой монадой, которая обеспечивает эту функциональность, но трансформаторы монады, такие как RouteT Также есть HasRqData случаи, которые делают подъем автоматически.

Итак, ваша оригинальная функция generate_page_Output работает, если вы дадите ей тот же тип возврата, что и route

generate_page_Output :: RouteT LambdaURL (ServerPartT IO) Response
generate_page_Output = do
  decodeBody (defaultBodyPolicy "." 0 65536 65536)
  expr <- look "expr"
  ok $ toResponse $ page_Output expr

нет lifeRouteT требуется.

Страница вывода, вероятно, 404, потому что вы не указали expr значение для look найти, так что не получается. Если вы хотите expr чтобы быть необязательным, то вы должны сделать:

  expr <- optional $ look "expr"

который сделает expr Maybe значение. optional происходит от Control.Applicative,

Вот рабочая версия:

{-# LANGUAGE OverloadedStrings #-}
module Main where

import Control.Applicative
import Data.Monoid
import Happstack.Server
import Happstack.Server
import Text.Blaze.Html5 ((!))
import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as A
import Web.Routes
import Web.Routes.Happstack


data LambdaURL =
  URL_CSS   |
  URL_Input |
  URL_Output

instance PathInfo LambdaURL where
  toPathSegments url =
    case url of
      URL_CSS    -> ["Main.css"]
      URL_Input  -> ["Input.html"]
      URL_Output -> ["Output.html"]

  fromPathSegments =
    (segment "Main.css"    >> return URL_CSS   ) <|>
    (segment "Input.html"  >> return URL_Input ) <|>
    (segment "Output.html" >> return URL_Output)

route :: LambdaURL -> RouteT LambdaURL (ServerPartT IO) Response
route url =
  case url of
    URL_CSS    -> serveFile (asContentType "text/css") "Main.css"
    URL_Input  -> ok $ toResponse $ page_Input
    URL_Output -> generate_page_Output

main = simpleHTTP nullConf $ implSite "www.example.com" "" (setDefault URL_Input $ mkSitePI (runRouteT route))

page_Input :: H.Html
page_Input =
    H.html $ do
      H.head $ do
        H.title "input"
      H.body $ do
       H.p $ H.a ! A.href "Output.html?expr=foo" $ "output"


page_Output :: String -> H.Html
page_Output expr =
    H.html $ do
      H.head $ do
        H.title "output"
      H.body $ do
        H.p $ do "expr is: "
                 H.toHtml expr

generate_page_Output :: RouteT LambdaURL (ServerPartT IO) Response
generate_page_Output = do
  decodeBody (defaultBodyPolicy "." 0 65536 65536)
  expr <- look "expr"
  ok $ toResponse $ page_Output expr
Другие вопросы по тегам