Akka-HTTP - DSLにおける暗黙の型変換
2016-05-28
QiitaScalaAkkaAkka-HTTPakka.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 を明示する
このroute
がRoute
たるために、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
の引数に渡しているString
はPathMatcher[Unit]
に implicit conversion されるPathMatcher[L]
になる場合(path
に正規表現を渡すとか)もあり、その場合はDirective[L]
となるDirective[L]
はL => Route
な関数を受け取る
complete
の引数に渡しているString
はToResponseMarshallable
に implicit conversion される- 標準で用意されている Marshaller はPredefinedToEntityMarshallersを参照
- その他の型については自前で Marshaller を実装すれば良い
Directive[L]
をDirective.addByNullaryApply
によってRoute => Route
なFunction1
に implicit conversion される- 今回は
Directive0
、すなわちDirective[Unit]
なのでDirective.addByNameNullaryApply
が使われる Directive[L]
の場合はDirective.addDirectiveApply[L]
が使われる
- 今回は
from: https://qiita.com/petitviolet/items/5cf2b3d3defed0459b9e