我使用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发布于 2019-02-19 19:12:42
Servant's 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中运行DB操作,并将DB异常映射到ServantErr,以获得您想要的HTTP响应代码。
如何在捕获数据库异常后抛出ServantErr:https://haskell-servant.readthedocs.io/en/stable/tutorial/Server.html#failing-through-servanterr
https://stackoverflow.com/questions/54763143
复制相似问题