Rejections
This documentation is for release 0.9.0 (from 03/2012), which is built against Scala 2.9.1 and Akka 1.3.1 (see Requirements for more information). Most likely, this is not the place you want to look for information. Please turn to the main spray site at http://spray.io for more information about other available versions.
. . .
In the section about constructing Routes the ~
operator was introduced, which connects two routes in a way that
allows a second route to get a go at a request if the first route "rejected" it. The concept of "rejections" is used
by spray for maintaining a more functional overall architecture and in order to be able to properly handle all kinds
of error scenarios.
When a filtering directive, like the get
directive, cannot let the request pass through to its inner route because the
filter condition is not satisfied the directive doesn't immediately complete the request with an error response.
Doing so would make it impossible for other routes chained in after the failing filter to get a chance to handle the
request. Rather, failing filters "reject" the request (the same happens when a route explicitly calls
requestContext.reject(...)
).
After having been rejected by a route the request will continue to flow through the routing structure and possibly find
another route that can complete it. If there are more rejections all of them will be picked up and collected.
If, in the end, the request could not be completed the HttpService will receive a set of rejections from its main
route. It is then the job of the RejectionHandler
in the HttpService to create an appropriate error response for
the received rejections.
Essentially, when you combine directives and custom routes via nesting and the ~
operator, you build a routing structure
that forms a tree. When a request comes in it is injected into this tree at the root and flows down through all the
branches in a depth-first manner until either some node completes it or it is fully rejected.
Consider this schematic example:
val route =
a {
b {
c {
... // route 1
} ~
d {
... // route 2
} ~
... // route 3
} ~
e {
... // route 4
}
}
Here five directives form a routing tree. Route 1 will only be reached if directives a
, b
and c
all let the request
pass through. Route 2 will run if a
and b
pass, c
rejects and d
passes. Route 3 will run if a
and b
pass,
but c
and d
reject. Route 3 can therefore be seen as a "catch-all" route that only kicks in, if routes chained into
preceding positions reject. This mechanism can make complex filtering logic quite easy to implement: simply put the most
specific cases up front and the most general cases in the back.
- Home
- Requirements
- ... 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