如何在Yesod路由处理程序中使用自定义错误处理程序?

时间:2014-10-20 08:58:33

标签: haskell error-handling yesod

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

  • 页面
  • API

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

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

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

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

如果不创建具有自己的errorHandler的子网站,我该怎么做?

2 个答案:

答案 0 :(得分:1)

在阅读了有关如何捕获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

我对HCError感兴趣,因为它包含ErrorResponse(与errorHandler相同的类型)。

我在我的cabal文件中将exceptions库添加到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知识的人可以提供。

答案 1 :(得分:1)

虽然您的解决方案确实有效,但您可以改为使用runInputPostResult函数,该函数实际上是由某人在PR中添加的,与您发现的情况非常相似。