marcin_koss
marcin_koss

Reputation: 5882

How does path method work in akka-http

This is more of a Scala question but inspired by this http-scala example.

val route =
      path("hello") {
        get {
          complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>"))
        }
      }

Based on example path seems like it could be a curried method that takes String as first argument and Route as second although I do not see such implementation in the API. Could someone enlighten me how this works?

Link to docs: http://doc.akka.io/api/akka-http/current/akka/http/javadsl/server/Directives$.html#path(segment:String,inner:java.util.function.Supplier[akka.http.javadsl.server.Route]):akka.http.javadsl.server.Route

Upvotes: 0

Views: 576

Answers (1)

No, path is not a curried function. The API gives the signature:

def path[L](pm: PathMatcher[L]): Directive[L]

Path is a simple unary function that takes in a PathMatcher and returns a Directive. Path only seems like it is a curried function because Directive has an apply method which makes it appear to be a function, but it's actually a class.

PathMatcher

By importing Directives._ the following implicit function becomes available:

implicit def _segmentStringToPathMatcher(segment: String): PathMatcher0

Note: PathMatcher0 is defined as PathMatcher[Unit] since it does not pass the matched value along to the inner Route.

Calling path with the argument in the example, path("hello"), is similar to following code:

val directive : Directive[Unit] = path(_segmentStringToPathMatcher("hello")) 

Directive

As stated previously, the Directive has an apply method that lazily takes in a Route:

def apply(v1 : => Route) : Route

So your example code is essentially making the following call:

val route = 
  directive.apply(get {
                    complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>"))
                  })

Putting It All Together

Let's simplify the definition of Route and mock some logic to demonstrate what is happening:

type SimpleRoute : HttpRequest => RouteResult

We can now write a version of path using a higher order function. Our simpler version takes in a String and returns a function instead of a Directive. It gets a little tricky because the returned function is also higher order:

def simplePath(pathStr : String) : SimpleRoute => SimpleRoute = 
  (innerRoute : SimpleRoute) => {

    //this is the returned SimpleRoute
    (request : HttpRequest) => {
      if(request.uri.path.toString equalsIgnoreCase pathStr)
        RouteResult.Complete(innerRoute(request))
      else
        RouteResult.Rejected(Seq.empty[Rejection])
    }

  }

Upvotes: 2

Related Questions