简体   繁体   中英

What Happend In Akka-Http DSL?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM