【问题标题】:How can I use a custom error handler in a Yesod route handler?如何在 Yesod 路由处理程序中使用自定义错误处理程序?
【发布时间】:2014-10-20 08:58:32
【问题描述】:

我有一个项目有两个部分:

  • 网页
  • API

我在我的Yesod 实例声明中使用errorHandler 函数在出现问题时为网页构建错误页面。

但是,API 中的所有路由都会创建 JSON 响应。我正在使用runInputPost 来生成处理API 输入的输入表单。当调用缺少参数的 API 时,Yesod 会生成 InvalidArgs 异常并返回错误 HTML 页面。

我希望能够处理该异常并返回JSON,例如:

{
  "success" : False,
  "code"    : 101,
  "message" : "The argument 'blabla' was missing"
}

如果不使用自己的 errorHandler 创建子网站,我该如何做到这一点?

【问题讨论】:

    标签: haskell error-handling yesod


    【解决方案1】:

    虽然您的解决方案确实有效,但您可以改用 runInputPostResult 函数,该函数实际上是由处于与您发现自己的情况几乎相同的人通过 PR 添加的。

    【讨论】:

    • 酷!下次我在我的项目中碰到 yesod 版本时会调查一下。谢谢!
    • 作为记录,该功能已经存在了一段时间。
    • 更好 :) 我接受这个答案,因为它是 Yesod 中已经存在的解决方案。
    【解决方案2】:

    在阅读了如何捕获 monad 堆栈中发生的异常(herehere)之后,我发现了似乎很容易使用的库 exceptions

    我读到Yesod 中的哪个类型实现了Exception 类型类,结果发现它是一个名为HandlerContents 的类型:

    data HandlerContents =
          HCContent H.Status !TypedContent
        | HCError ErrorResponse
        | HCSendFile ContentType FilePath (Maybe FilePart)
        | HCRedirect H.Status Text
        | HCCreated Text
        | HCWai W.Response
        | HCWaiApp W.Application
        deriving Typeable
    

    我对@9​​87654330@ 感兴趣,因为它包含ErrorResponse(与errorHandler 获得的类型相同)。

    我将exceptions 库添加到我的cabal 文件中的build-depends。我在 API 中的所有处理程序都有签名 :: Handler Value,所以我创建了一个名为 catchRouteError 的实用程序函数,我可以使用它来运行我的处理程序:

    catchRouteError :: Handler Value -> Handler Value
    catchRouteError r = catch r handleError
      where
        handleError :: HandlerContents -> Handler Value
        handleError (HCError (InvalidArgs _)) = ... create specific json error
        handleError (HCError _)               = ... create generic json error
        handleError e                         = throwM e
    

    由于HandlerContents 用于其他事情,例如重定向和接收文件,我只匹配HCError 并让默认实现处理其他所有事情。

    现在我可以使用这个函数轻松运行我的处理程序:

    postAPIAppStatusR :: Handler Value
    postAPIAppStatusR = catchRouteError $ do
        ...
    

    这是我的问题的快速解决方案,我相信有更好的Yesod 知识的人可以提供更优雅的解决方案。

    【讨论】:

    • 填写... - 你可能想要这样的东西:sendResponseStatus status400 (object [ "error_invalid" .= show a ]) 如果你只返回一个 Aeson 值,你会得到一个200 响应,这不太正确。
    • 感谢您的意见,马克!
    猜你喜欢
    • 1970-01-01
    • 2017-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-29
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多