-
Notifications
You must be signed in to change notification settings - Fork 0
Composing Directives
As you have seen from the examples presented so far the "normal" way of composing directives is nesting. Let's take another look at the example from the Directives page:
val route: Route =
path("order" / HexIntNumber) { id =>
get {
completeWith {
"Received GET request for order " + id
}
} ~
put {
completeWith {
"Received PUT request for order " + id
}
}
}Here the get and put directives are chained together with the ~ operator to form a higher-level route that serves
as the inner route of the path directive. To make this structure more explicit you could also write the whole thing
as such:
def innerRoute(id: Int): Route =
get {
completeWith {
"Received GET request for order " + id
}
} ~
put {
completeWith {
"Received PUT request for order " + id
}
}
val route: Route = path("order" / HexIntNumber) { id => innerRoute(id) }What you can't see from this snippet is that directives are not implemented as simple methods but rather as stand-alone
objects (of a SprayRoute subtype). This gives you more flexibility when composing directives. For example you can
also use the | operator on directives.
Here is yet another way to write the example:
val route =
path("order" / HexIntNumber) { id =>
(get | put) { ctx =>
ctx.complete("Received " + ctx.request.method + " request for order " + id)
}
}If you have a larger route structure where the (get | put) snippet appears several times you could also factor it out
like this:
val getOrPut = get | put
val route =
path("order" / HexIntNumber) { id =>
getOrPut { ctx =>
ctx.complete("Received " + ctx.request.method + " request for order " + id)
}
}As an alternative to nesting you can also use the & operator:
val getOrPut = get | put
val route =
(path("order" / HexIntNumber) & getOrPut) { id => ctx =>
ctx.complete("Received " + ctx.request.method + " request for order " + id)
}And once again, you can factor things out if you want:
val orderGetOrPut = path("order" / HexIntNumber) & (get | put)
val route =
orderGetOrPut { id => ctx =>
ctx.complete("Received " + ctx.request.method + " request for order " + id)
}This type of combining directives with the | and & operators as well as "saving" more complex directive
configurations as a val works across the board, with almost all directives taking inner routes.
Thereby spray makes sure that all extractions work as expected and logical constraints are enforced at compile-time.
For example you cannot | a directive producing an extraction with one that doesn't:
val route = path("order" / IntNumber) | get // doesn't compileAlso the extraction types have to match up:
val route = path("order" / IntNumber) | path("order" / DoubleNumber) // doesn't compile
val route = path("order" / IntNumber) | parameter('order.as[Int]) // okWhen you combine directives producing extractions with the & operator all extractions will be properly gathered up:
val order = path("order" / IntNumber) & parameters('oem, 'expired ?)
val route =
order { (orderId, oem, expired) =>
...
}Summing up, directives offer a great way of constructing your web service logic from small building blocks in a plug and play fashion while maintaining DRYness and full type-safety. If the large range of predefined directives does not fully satisfy your needs you can also very easily create Custom Directives.
- Home
- Requirements
- spray-server
- ... Getting Started
- ... Key Concepts
- ...... Request Lifecycle
- ...... Routes
- ...... Directives
- ...... Composing Directives
- ...... Rejections
- ...... Marshalling and Unmarshalling
- ... Predefined Directives
- ...... Method Filters
- ...... Path Filters
- ...... Parameter Filters
- ...... Form-Field Filters
- ...... Marshalling/Unmarshalling
- ...... Caching
- ...... Detach
- ...... Encoding/Decoding
- ...... Authentication/Authorization
- ...... File and Resource Directives
- ...... Misc Directives
- ... Advanced Topics
- ...... Case Class Extraction
- ...... Custom Directives
- ...... Custom Media Types
- ...... Custom Error Responses
- ... Configuration
- ... Testing
- ... Example Projects
- spray-client
- Patch Policy
- Credits
- Sponsors