IT練習ノート

IT関連で調べたこと(実際は嵌ったこと)を書いています。

ServantのルーティングでのIO

Servanthandlerでの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

このwithRequestIOを使うコードを下記を参考に追加してみました。lift自体はControl.Monad.BaseliftBaseを使います。

元ネタ

Jacob Errington | Token authentication with Servant

IOを追加したコード

Token Authentication with Servant with IO