I'm using Servant with custom monad stack:
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 }
Now, in many handlers I just need to do fetch some data (Persistent) from db and act upon it, so I've got:
runDb :: (MonadReader Config m, MonadIO m) => SqlPersistT IO b -> m b
runDb query = do
pool <- asks getPool
liftIO $ runSqlPool query pool
As it turns out, when fetching from db, you're bound to work with Maybe
, and quite often when the Maybe is Nothing
, you just want to throw error so that Servant server will turn it into proper HTTP response. This led me to the discovery of Control.Error.Util
and the (!?) :: Applicative m => m (Maybe a) -> e -> ExceptT e m a
helper. So I tried following:
someHandler :: AppHandler NoContent
someHandler = do
entity <- (runDb $ getCompanyByName companyName) !? err400
-- some more logic
return NoContent
But this does not compile, the result of !?
here is ExceptT ServantErr m0 (Entity SomeEntity)
but I no longer work with such handler type, it requires the AppHandler (Entity SomeEntity)
. How would I convert such value back to my handler type?