spray-routing is build around the concept of Directive
.
You can think of a Directive
as a transformation over an HTTP request.
The cardinality associated with a directive is the number of arguments is passes down the transform chain after performing the transformation.
Directive0
is a directive that doesn't provide (or extract) any argument.
Directive1[A]
provides one argument of type A
.
Directive[A :: B :: HNil]
provides 2 arguments of types A
and B
, or - to be more precise - provides an heterogeneous list made of A
and B
(the implementation is a shapeless's HList
).
Let's take the examples in your code
val twoIntParameters: Directive[Int :: Int :: HNil] =
parameters('a.as[Int], 'b.as[Int])
You're defining a new directive that extracts two integers from the HTTP request, i.e. has the type Directive[Int :: Int :: HNil]
.
The implementation simply leverages a directive provided already by spray, i.e. parameters
.
parameters
is a directive that allows to extract the query parameters from a HTTP request and convert them to a specific type, in this case Int
for both parameters.
val myDirective: Directive1[String] =
twoIntParameters.hmap {
case a :: b :: HNil => (a + b).toString
}
myDirective
is a directive that extracts one parameter of type String
.
Its implementation uses the previously defined twoIntParameters
directive and maps over its result, applying a transformation to it.
In this case we're taking the two Int
, summing them and turning the result into a String
.
So, what's with the hmap
? That's just a way provided by spray of working with Directives that return a shapeless HList
. hmap
requires a function that HList
to anything, in this case a String
.
HList
s can be pattern matched over, just like a normal scala List
, and that's what you're seeing in the example.
Finally, this is just an idea of how directives work from a functional point of view.
If you want to understand the fine details of the DSL syntax, you will have to dig a little further and read about the Magnet Pattern.