ServantのルーティングでのIO
Servant
でhandler
でのIO
の取り回しのサンプルはWebに情報があるのですが、:>
で記述していくルーティングでのIO
の取り回しがわからず四苦八苦していました。
HasServer
という型クラスでルーティングを記述していきますが、このクラス自体にIO
が明示的にはない(と思う)ので、ルーティング中にデータベースとかにアクセスしたい場合どうするのかと疑問に思っていました。ソースを読んでも、Delayed
という処理を貯めといて最後に処理をする仕組みのため、なかなかコードが読めませんでした。
さらにDelayed
のコードを読むとデータコンストラクタ中にDelayedIO
があります。これが、隠蔽化されているようにも思えますが、DelayedIO
定義自体は隠蔽化はしていません。DelayedIO
という名前にIO
がついているので、これを使えばIO
ができることは推測できるのですが、具体的にどうすればよいかわかりませんでした。
DelayedIO
の定義をみると、モナドトランスフォーマーのスタックの最後(最初?)にIO
があるので、これが目標になります。結局、lift
してやればIO
ができるということでした。
newtype DelayedIO a = DelayedIO { runDelayedIO' :: ReaderT Request (ResourceT (RouteResultT IO)) a } deriving ( Functor, Applicative, Monad, MonadIO, MonadReader Request, MonadBase IO, MonadThrow, MonadResource)
DelayedIO
を手繰り寄せるには、withRequest
が使えます。
Servant.Server.Internal.RoutingApplication
このwithRequest
でIO
を使うコードを下記を参考に追加してみました。lift
自体はControl.Monad.Base
のliftBase
を使います。
元ネタ
Jacob Errington | Token authentication with Servant
IO
を追加したコード