In this blog we’ll be discussing about the Routing DSl provided by Akka HTTP High level Server Side API.
Akka HTTP provides a very flexible “Routing DSL” for elegantly defining RESTful web services. It picks up where the low-level API leaves off and offers much of the higher level functionality of typical web servers or frameworks, like deconstruction of URIs, content negotiation or static content serving.
-> Why do we need Routing DSL ?
The Akka HTTP Low-Level Server-Side API provides a Flow- or Function-level interface that allows an application to respond to incoming HTTP requests by simply mapping requests to responses:
case HttpRequest(GET, Uri.Path("/ping"), _, _, _) => HttpResponse(entity = "PONG!") case HttpRequest(GET, Uri.Path("/pong"), _, _, _) => HttpResponse(entity = "PING!")
In the above case when the requested URI is “ping” case one follows and when URI is “pong” case two follows. Similarly we’ll have to write match cases for each and every URI as we are using pattern matching. It seems completely OK to write the complete REST API with pattern matching, but with larger services this approach becomes cumbersome and it also doesn’t keep your service definition DRY(Don’t Repeat Yourself).
As an alternative to the above approach Akka HTTP provided a flexible Routing DSL for defining our REST API very elegantly. It continues where the Low-Level Server API left.
-> How does it works ?
Akka HTTP uses Directives(small building blocks of Routing DSL) which are assembled together for creating complex route structure. There are already pre-defined large no. of directives available like(get, complete, post etc). We can also define custom directives as per our need. At the top level the route structure forms a handler Flow which can be directly passed to bind call.
The conversion from Route to flow can either be invoked explicitly using Route.handlerFlow or, the conversion is also provided implicitly by RouteResult.route2HandlerFlow.
If the above example implemented using Routing DSL, it can be done like following:
val route = get { path("ping") { complete("PONG!") } ~ path("pong") { complete("PING!") } }
Isn’t it more readable and DRY ? Now, as we have an idea of what Routing DSL is and how it works. lets move a step further. To understand more about Routing DSL we’ll have to understand what routes are. So the next question arises, what are Routes ?
The “Route” is the central concept of Akka HTTP’s Routing DSL. All the structures you build with the DSL, are instances of this type.
type Route = RequestContext ⇒ Future[RouteResult]
It’s a simple alias for a function turning a RequestContext into a Future[RouteResult].
When a route receives a request it can do following things to that request:
- Complete the request by returning the value of requestContext.complete(…).
- Reject the request by returning the value of requestContext.reject(…)
- Fail the request by returning the value of requestContext.fail(…) or by just throwing an exception.
- Do any kind of async processing and instantly return a Future[RouteResult] to be eventually completed later.
Here is an complete example to how to write service definition using Routing DSL:
import akka.http.scaladsl.model.HttpResponse import akka.http.scaladsl.model.StatusCodes._ import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route trait RequestHandler { def route: Route = pathPrefix("ping") { pathEnd { get { complete { HttpResponse(OK, entity = "PING") } } } ~ path("pong" / Segment) { id => get { complete { HttpResponse(OK, entity = s" PONG! $id") } } } } }
So, We just covered what Routing DSL is and its building blocks Routes and Directives , which helps us to make our REST API more elegant and DRY. Enjoy 🙂
Reblogged this on teena2015.