I just touched akka recently, when learning akka-http, I am attracted by the Rest API DSL, here is a piece of code:
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import scala.io.StdIn
object WebServer {
def main(args: Array[String]) {
implicit val system = ActorSystem("my-system")
implicit val materializer = ActorMaterializer()
// needed for the future flatMap/onComplete in the end
implicit val executionContext = system.dispatcher
val route =
path("hello") {
get {
complete("Say hello to akka-http")
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
StdIn.readLine() // let it run until user presses return
bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
.onComplete(_ => system.terminate()) // and shutdown when done
}
}
What I cannot understand is the val route = path("hello") {....}
. I know the “path” method will return a Directive, and the “get” method is also a Directive, but I can't understand how can a directive “embeds” in another directive by the braces “{}”.
I know, there must be some implicit conversions, by debugging, I saw, the following implicit conversion is applied: akka.http.scaladsl.server.Directive#addByNameNullaryApply
implicit def addByNameNullaryApply(directive: Directive0): (⇒ Route) ⇒ Route =
r ⇒ directive.tapply(_ ⇒ r)
Can anybody explain to me: how can this implicit conversion is selected and happened? And what dose the apply and tapply try to do? Thanks a lot!
First:
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
is equal to:
val bindingFuture = Http().bindAndHandle(Route.handlerFlow(route), "localhost", 8080)
the Route.handlerFlow
method is used to conversion Route
to Flow[HttpRequest, HttpResponse, NotUsed]
, as we see the bindAndHandle
accept handler
type is: Flow[HttpRequest, HttpResponse, Any]
the implicit conversion route
to Flow[HttpRequest, HttpResponse, NotUsed]
is implemented by the RouteResult.route2HandlerFlow
. and this is extended by Directives
and work with import akka.http.scaladsl.server.Directives._
.
so when you import Directives , you import this implicit conversions.
For addByNameNullaryApply
, we can rewrite code like the below:
...
val path1: Directive0 = path("hello")
val contextToEventualResult: Route = get(complete("Say hello to akka-http"))
val route: Route = path1.apply(contextToEventualResult)
...
as we can see, for path1.apply(contextToEventualResult)
it's calling a high-order function with applying contextToEventualResult
parameter. but for path1
's type is Directive0
, so:
implicit def addByNameNullaryApply(directive: Directive0): (⇒ Route) ⇒ Route
is used to convert the Directive0
type to a high order function with type: (⇒ Route) ⇒ Route
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.