3

给定以下代码:

newtype HelloMessage = HelloMessage { msg :: String }
  deriving (Generic)

instance ToJSON HelloMessage

type API2 = "hello"
            :> QueryParam "age" Int
            :> Get '[JSON] HelloMessage

appAPI2 :: Proxy API2
appAPI2 = Proxy

myHandler :: Server API2
myHandler = helloHandler
  where
    helloHandler :: Maybe Int -> Handler HelloMessage
    helloHandler mAge =
      let
        sAge = case mAge of
                 Nothing -> "0"
                 Just ag -> show ag
      in
        return . HelloMessage $ sAge

app2 :: Application
app2 = serve appAPI2 myHandler

main :: IO ()
main = run 8080 app2

我可以访问/hellowhich return{ "msg" : 0}/hello?age=20which returns { "msg" : 20}。但是,如果我将年龄设置为不可解析的非整数,例如"foobar"使 url 成为/hello?age=foobar并访问它,它会返回一条关于解析错误的错误消息"foobar"

如果我给予相同的处理,它的行为会有所不同,Capture它只会返回一个 http 400。

我的代码有什么问题?

编辑:经过进一步探索,它确实在解析错误时返回 http 400。现在我换个问题。如果发生这种情况,如何返回自定义错误消息?

4

1 回答 1

6

的默认行为QueryParam是这样的:如果您无法解码,则出错,但在未指定时返回 Nothing。

从servant 0.13 开始,您可以覆盖它。

如果您查看的定义QueryParamQueryParam',您会发现它实际上只是更一般类型的特例:

type QueryParam = QueryParam' '[Optional, Strict]

QueryParam'采用我们所说的“修饰符”,它影响两件事:

  • 如果没有此参数的值,您是否可以生存:如果可以,您的处理程序将获得 a Maybe a,如果不是,您将直接获得 ana但是当没有给出值时它会出错。这是RequiredOptional
  • 无论您是否希望解码失败是致命的:如果您这样做,那么当解码失败时,servant 会为您输出错误,否则您的处理程序会得到一个a. 如果你不这样做,那么你的处理程序会得到一个,然后你可以Either Text a在出现解码错误的情况下自由地做任何你想做的事情(这是 的Left情况Either,带有文本错误消息)。这是StrictLenient

所以你可能想定义类似的东西type MyQueryParam name a = QueryParam' '[Optional, Lenient]并在适当的时候使用它。

这能解决你的问题吗?

于 2018-07-03T08:36:19.617 回答