将 failWith 与 Servant 和自定义 monad 堆栈一起使用
Using failWith with Servant and custom monad stack
我正在使用 Servant 和自定义 monad 堆栈:
newtype AppHandler a = AppHandler { runHandler :: ReaderT Config (ExceptT ServantErr IO) a }
deriving (Functor, Applicative, Monad, MonadReader Config, MonadError ServantErr, MonadIO)
data Config = Config
{ getPool :: ConnectionPool }
现在,在许多处理程序中,我只需要从数据库中获取一些数据(持久性)并对其进行操作,所以我得到了:
runDb :: (MonadReader Config m, MonadIO m) => SqlPersistT IO b -> m b
runDb query = do
pool <- asks getPool
liftIO $ runSqlPool query pool
事实证明,当从数据库中获取数据时,您必然会使用 Maybe
,并且通常当 Maybe 为 Nothing
时,您只想抛出错误以便 Servant服务器会将其转换为正确的 HTTP 响应。这让我发现了 Control.Error.Util
和 (!?) :: Applicative m => m (Maybe a) -> e -> ExceptT e m a
助手。所以我尝试了以下:
someHandler :: AppHandler NoContent
someHandler = do
entity <- (runDb $ getCompanyByName companyName) !? err400
-- some more logic
return NoContent
但这不会编译,这里 !?
的结果是 ExceptT ServantErr m0 (Entity SomeEntity)
但我不再使用这种处理程序类型,它需要 AppHandler (Entity SomeEntity)
。我如何将此类值转换回我的处理程序类型?
通常要将类型 m a
的值转换为 ReaderT r m a
只需使用 lift
.
所以也许这对你有用:
entity <- lift $ (runDb $ getCompanyByName companyName) !? err400
如果整个 (runDb ...) !? err400
是一个 ExceptT ServantError ...
值。
另外,本仆问题讨论:
https://github.com/haskell-servant/servant/issues/286
可能会有帮助。
你想要一个 (!?)
的变体,它是多态的,其中 monad returns。例如:
(!??) :: MonadError e m => m (Maybe a) -> e -> m a
act !?? err = act >>= maybe (throwError err) return
然后,提供 err400 :: ServantError
-- 这是您声明 AppHandler
的错误类型 -- 您将能够编写
runDb (getCompanyByName companyName) !?? err400
我正在使用 Servant 和自定义 monad 堆栈:
newtype AppHandler a = AppHandler { runHandler :: ReaderT Config (ExceptT ServantErr IO) a }
deriving (Functor, Applicative, Monad, MonadReader Config, MonadError ServantErr, MonadIO)
data Config = Config
{ getPool :: ConnectionPool }
现在,在许多处理程序中,我只需要从数据库中获取一些数据(持久性)并对其进行操作,所以我得到了:
runDb :: (MonadReader Config m, MonadIO m) => SqlPersistT IO b -> m b
runDb query = do
pool <- asks getPool
liftIO $ runSqlPool query pool
事实证明,当从数据库中获取数据时,您必然会使用 Maybe
,并且通常当 Maybe 为 Nothing
时,您只想抛出错误以便 Servant服务器会将其转换为正确的 HTTP 响应。这让我发现了 Control.Error.Util
和 (!?) :: Applicative m => m (Maybe a) -> e -> ExceptT e m a
助手。所以我尝试了以下:
someHandler :: AppHandler NoContent
someHandler = do
entity <- (runDb $ getCompanyByName companyName) !? err400
-- some more logic
return NoContent
但这不会编译,这里 !?
的结果是 ExceptT ServantErr m0 (Entity SomeEntity)
但我不再使用这种处理程序类型,它需要 AppHandler (Entity SomeEntity)
。我如何将此类值转换回我的处理程序类型?
通常要将类型 m a
的值转换为 ReaderT r m a
只需使用 lift
.
所以也许这对你有用:
entity <- lift $ (runDb $ getCompanyByName companyName) !? err400
如果整个 (runDb ...) !? err400
是一个 ExceptT ServantError ...
值。
另外,本仆问题讨论:
https://github.com/haskell-servant/servant/issues/286
可能会有帮助。
你想要一个 (!?)
的变体,它是多态的,其中 monad returns。例如:
(!??) :: MonadError e m => m (Maybe a) -> e -> m a
act !?? err = act >>= maybe (throwError err) return
然后,提供 err400 :: ServantError
-- 这是您声明 AppHandler
的错误类型 -- 您将能够编写
runDb (getCompanyByName companyName) !?? err400