カスタムモナドスタックでServantを使用しています:
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 }
さて、多くのハンドラーでは、db からいくつかのデータ (Persistent) をフェッチしてそれに基づいて処理する必要があるだけなので、次のようになります。
runDb :: (MonadReader Config m, MonadIO m) => SqlPersistT IO b -> m b
runDb query = do
pool <- asks getPool
liftIO $ runSqlPool query pool
結局のところ、db からフェッチするときは を使用する必要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)
です。そのような値をハンドラーの型に戻すにはどうすればよいですか?