在仆人中捕获IO异常

时间:2019-02-19 09:45:28

标签: haskell servant

我将servant用于简单的JSON api,它使您可以创建名称必须唯一的用户。这是由SQLite中的唯一约束强制执行的。我有一个函数DB.saveUser :: UserReq -> IO Int(毫不奇怪)将用户保存到SQLite并返回生成的ID。如果名称已被使用,它将抛出SQLError ErrorConstraint _ _。如果发生这种情况,我想返回HTTP响应代码409。所以我的问题是,有没有办法在Handler Monad中捕获SQLError?如果没有,实现我所寻找的最干净的方法是什么?我曾考虑过让DB.saveUser返回Maybe Int,但我认为必须有一个更好的解决方案。

createUser :: UserReq -> Handler (Headers '[Header "Location" Text] NoContent)
createUser ur = do id <- liftIO (DB.saveUser ur)
                   return . addHeader (T.pack ("/user/" ++ show id)) $ NoContent

saveUser (UR.UserReq name) = withConnection database $ \conn ->
  do executeNamed conn "INSERT INTO users (name) VALUES (:name)" [":name" := name]
     fromIntegral <$> lastInsertRowId conn

1 个答案:

答案 0 :(得分:2)

仆人的Handler是新型包装器:

newtype Handler a = Handler { runHandler' :: ExceptT ServantErr IO a }

内部有一个ExceptT ServantErr,其中ServantErr是:

data ServantErr = ServantErr { errHTTPCode     :: Int
                             , errReasonPhrase :: String
                             , errBody         :: LBS.ByteString
                             , errHeaders      :: [HTTP.Header]
                             } deriving (Show, Eq, Read, Typeable)

因此,您可以在try中运行数据库操作,或者处理bracket的释放资源,并将数据库异常映射到ServantErr以获得您的HTTP响应代码想要。

如何在捕获数据库异常后抛出ServantErrhttps://haskell-servant.readthedocs.io/en/stable/tutorial/Server.html#failing-through-servanterr

相关问题