I am new to spray. I have work with several strange (for me) programming languages like python, JQuery, etc... With them I could at least understand what some code segment do. Unfortunately with Spray, I can not read and understand even a simple code.
Could some one please help me to read (describe with word, what the code do) the following simple code block.
Note: Very high level I know, this will pick the url parameter and add them together. But what I want is, understand this code block crystal clearly, as I could teach to someone else. HNil, Directive1, Directive1, ::
are some what strange for me.
val twoIntParameters: Directive[Int :: Int :: HNil] =
parameters('a.as[Int], 'b.as[Int])
val myDirective: Directive1[String] =
twoIntParameters.hmap {
case a :: b :: HNil => (a + b).toString
}
// test `myDirective` using the testkit DSL
Get("/?a=2&b=5") ~> myDirective(x => complete(x)) ~> check {
responseAs[String] === "7"
}
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.