Jay Taylor's notes
back to listing indexPath Filters · spray/spray Wiki
[web search]Path Filters · spray/spray Wiki
Deprecation Note
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.
Path filter directives filter requests based on the unmatched part of the request URIs path component (i.e. without scheme, host and query part). They come in two flavors:
- The
path
directive applies a match expression to the complete unmatched path of the request. - The
pathPrefix
directive does the same but tries to only match a path prefix.
Both directives take one argument of type PathMatcher, which is usually specified as a filter expression written in a mini-DSL.
The PathMatcher DSL
Just like spray routes are built from directives as building blocks more complex "PathMatchers" are created by combining simpler "PathMatchers" with operators.
By default the following things can be used as "atomic" PathMatchers:
Simple Strings They simply match themselves and extract no value.
The
PathElement
object It matches one or more arbitrary characters except/
and is therefore equivalent, but more efficient, than a regex match"[^/]+".r
.Regular expressions They match whatever they match and extract one
String
value, which is either the complete match (if the regex contains no capturing group) or the captured group (if the regex contains a capturing group).The objects
IntNumber
,LongNumber
,HexIntNumber
,HexLongNumber
,DoubleNumber
They match either anInt
,Long
orDouble
literal and extract its value.The
Remaining
object It matches all remaining, unmatched characters of the request path and extracts them as aString
value.The
JavaUUID
object It matches the string representation of ajava.util.UUID
instance and extracts it.The result of the
pathMatcher(Map[String, T])
method This method creates a PathMatcher from the given Map. If the unmatched path starts with one of the maps keys the matcher consumes this path prefix and extracts the corresponding map value.
"PathMatchers" can be chained with the /
or ~
operators. The difference between the two is that /
also matches a
separating slash character whereas ~
simply connects two "PathMatchers" without any additional logic.
Note that each call to a path
or pathPrefix
directive implies a leading slash match, so you never have to start
your PathMatcher argument with a slash.
Examples
The following route only responds to requests to paths beginning with "/hello" (note that you do not have to specify the
initial slash /
character):
pathPrefix("hello") { ... }
The following three routes all respond to requests to "/hello/bob":
path("hello/bob") { ... } path("hello" / "bob") { ... } pathPrefix("hello") { path("bob") { // the leading slash before "bob" is implied ... } }
Regular expression matches (without capturing groups):
path("order" / "\\d+".r) { id => // 'id' contains the string of matched digits _.complete("The order id is: " + id) } pathPrefix("employee" / PathElement) { employee => path("salary" / "\\d\\d\\d\\d".r / "\\d\\d".r) { (year, month) => ... } ~ path("tenure") { ... } }
Regex match with capturing group:
path("order(\\d+)".r) { id => ... // 'id' contains the string of matched digits }
Chaining several regex matches:
path("post-" ~ "\\d\\d\\d\\d".r ~ "-(\\d\\d)".r ~ "-(\\d\\d)".r) { (year, month, day) => ... // responds for example to "/post-2011-03-23" }
Matching and extracting Int
values:
pathPrefix("order") { path("i" ~ IntNumber) { intNum => ... } ~ path("h" ~ HexIntNumber) { intNum => ... } }
Custom PathMatchers
If you often have to match and extract custom objects from the request path it probably makes sense to create a custom
PathMatcher for your type. In many cases the easiest way for this is to reuse a regex matcher and wrap it with a
string-to-type conversion. You might want to use the implementation of the DoubleNumber
matcher as a starting point:
/** * A PathMatcher that matches and extracts a Double value. The matched string representation is the pure decimal, * optionally signed form of a double value, i.e. without exponent. */ object DoubleNumber extends PathMatcher1[Double] { private val regexMatcher = new SimpleRegexMatcher("""[+-]?\d*\.?\d*""".r) def apply(path: String) = { // use 'flatMapValue' on the result of any PathMatcher1 to convert the extracted value to another type regexMatcher(path).flatMapValue { string => try { Some(java.lang.Double.parseDouble(string)) } catch { case _: NumberFormatException => None } } } }