LoginSignup
2
2

More than 5 years have passed since last update.

[Akka-HTTP]DSLにおける暗黙の型変換

Posted at

akka.http.scaladslパッケージをimportすることで使えるようになるDSLが、
裏側でどのように実装されているか気になったので調べた。

題材

akka-httpにおいて、単純なルーティングについて考えてみる。

val route = path("ping") {
  get {
    complete("pong")
  }
}

localhost:8080/pingにGETリクエストを送ると期待通りにpongと返ってくる。

$ curl localhost:8080/ping
pong

implicit conversionを明示する

このrouteRouteたるために、implicit conversionがふんだんに使われている。
implicitなconversionを明示的にして変数に束縛して型注釈をつけるとこうなる。

// path
val pingSegment: String = "ping"
val pingMatcher: PathMatcher[Unit] = ImplicitPathMatcherConstruction.segmentStringToPathMatcher(pingSegment)
val pingDirective: Directive[Unit] = path(pingMatcher)

// response
val pongStr: String = "pong"
val pongMarshal: ToResponseMarshallable =
  ToResponseMarshallable.apply(pongStr)(PredefinedToEntityMarshallers.StringMarshaller)
val pongStandardRoute: StandardRoute = complete(pongMarshal)

// construct route
val getPingPath: StandardRoute => Route = s =>
  Directive.addByNameNullaryApply(MethodDirectives.get)(s)
val pingRoute: Route = getPingPath(pongStandardRoute)
val pingRouter: (=> Route) => Route = Directive.addByNameNullaryApply(pingDirective)
val route: Route = pingRouter(pingRoute)

思ったより量が多くなった。
なおimplicit conversionを明記だけなら多少は読みやすくなる。

Directive.addByNameNullaryApply(path(ImplicitPathMatcherConstruction.segmentStringToPathMatcher("ping"))) {
  Directive.addByNameNullaryApply(MethodDirectives.get) {
    complete(ToResponseMarshallable("pong"))
  }
}

DSLはどのようにimplicit conversionされているか

実際にDSLを使用するだけであれば特に意識する必要はないが、DSLの裏で行われていることをざっとまとめると以下。

  • pathの引数に渡しているStringPathMatcher[Unit]にimplicit conversionされる
    • PathMatcher[L]になる場合(pathに正規表現を渡すとか)もあり、その場合はDirective[L]となる
    • Directive[L]L => Routeな関数を受け取る
  • completeの引数に渡しているStringToResponseMarshallableにimplicit conversionされる
    • 標準で用意されているMarshallerはPredefinedToEntityMarshallersを参照
    • その他の型については自前でMarshallerを実装すれば良い
  • Directive[L]Directive.addByNullaryApplyによってRoute => RouteFunction1にimplicit conversionされる
    • 今回はDirective0、すなわちDirective[Unit]なのでDirective.addByNameNullaryApplyが使われる
    • Directive[L]の場合はDirective.addDirectiveApply[L]が使われる
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2