Servant QueryParams 解析错误

Servant QueryParams parse error

给定以下代码:

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

我可以访问 /hello,其中 return 是 { "msg" : 0}/hello?age=20,其中 return 是 { "msg" : 20}。但是,如果我将年龄设置为可解析的非整数,例如"foobar" 这使得 url 成为 /hello?age=foobar 并访问它,它 return 是关于 "foobar".

上的解析错误的错误消息

这与 Capture 的行为不同,如果我给予相同的处理,它只会 return 一个 http 400。

我的代码有什么问题?

编辑:经过进一步探索,它确实 return http 400 解析错误。现在我正在改变问题。如何 return 自定义错误信息 if 那会发生吗?

QueryParam 的默认行为是这样的:如果无法解码则出错,但 return 未指定时无任何内容。

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

如果你查看 the definition of QueryParam,你会发现它实际上只是更一般的 QueryParam' 类型的特例:

type QueryParam = QueryParam' '[Optional, Strict]

QueryParam' 采用我们所说的 "modifiers",这会影响两件事:

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

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

这是否解决了您的问题?