如何在仆人处理程序 monad 中处理异常?

How to handle exception within a servant handler monad?

我想在服务处理程序 monad 中处理数据库异常。

我尝试使用 Control.Exception 包中的 try 函数来与 Left exception -> throwError err422 { errBody = ... } 进行大小写匹配。

我正在使用 postgresql-typed to interface with a PostgreSQL database. I want to capture a PGError 例外。

relevant code进行如下修改:

accountHandler :: CreateAccountPayload -> Handler Account
accountHandler payload =
  let errors = validateCreateAccountPayload payload in
  if hasErrors errors then
    throwError err422 { errBody = JSON.encode errors }
  else
    do
      result <- try (liftIO (insertAccount payload))
      case result of
        Right account -> return account
        Left exception -> throwError err422 { errBody = JSON.encode [ValidationError (Text.pack "email") (Text.pack "is already taken")] }

我希望能够从数据库调用中捕获结果并能够对其进行大小写匹配。这些案例应该是针对异常或值的。我目前收到以下编译错误:

src/Main.hs:64:17: error:
    • Couldn't match type ‘IO’ with ‘Handler’
      Expected type: Handler (Either e0 Account)
        Actual type: IO (Either e0 Account)
    • In a stmt of a 'do' block:
        result <- try (liftIO (insertAccount payload))
      In the expression:
        do result <- try (liftIO (insertAccount payload))
           case result of
             Right account -> return account
             Left exception -> throwError err422 {errBody = encode ...}
      In the expression:
        if hasErrors errors then
            throwError err422 {errBody = encode errors}
        else
            do result <- try (liftIO (insertAccount payload))
               case result of
                 Right account -> return account
                 Left exception -> throwError ...
   |
64 |       result <- try (liftIO (insertAccount payload))
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我认为 liftIO 将您的 IO Account 结果提升到 Handler monad。如果是这样,也许 try 应该先行,liftIO 第二:

result <- liftIO (try (insertAccount payload))
case result of
    Right account -> return account
    Left (PGError e) -> throwError err422