parameters
This page explains how to extract multiple query parameter values from the request, or parameters that might or might not be present.
Signature
def parameters(param: <ParamDef[T]>): Directive1[T]
def parameters(params: <ParamDef[T_i]>*): Directive[T_0 :: ... T_i ... :: HNil]
def parameters(params: <ParamDef[T_0]> :: ... <ParamDef[T_i]> ... :: HNil): Directive[T_0 :: ... T_i ... :: HNil]
The signature shown is simplified and written in pseudo-syntax, the real signature uses magnets. [1] The type <ParamDef>
doesn’t really exist but consists of the syntactic variants as shown in the description and the examples.
[1] See The Magnet Pattern for an explanation of magnet-based overloading.
Description
The parameters directive filters on the existence of several query parameters and extract their values.
Query parameters can be either extracted as a String or can be converted to another type. The parameter name is supplied as a String. Parameter extraction can be modified to mark a query parameter as required, optional, or repeated, or to filter requests where a parameter has a certain value:
"color"
- extract the value of parameter “color” as
String
- reject if the parameter is missing
"color".optional
- (symbolic notation
"color".?
) - extract the optional value of parameter “color” as
Option[String]
"color".withDefault("red")
- (symbolic notation
"color" ? "red"
) - extract the optional value of parameter “color” as
String
with default value"red"
"color".requiredValue("blue")
- (symbolic notation
"color" ! "blue"
) - require the value of parameter “color” to be
"blue"
and extract nothing - reject if the parameter is missing or has a different value
"amount".as[Int]
- extract the value of parameter “amount” as
Int
, you need a matchingUnmarshaller
Unmarshaller
in scope for that to work (see also Unmarshalling) - reject if the parameter is missing or can’t be unmarshalled to the given type
"amount".as(unmarshaller)
- extract the value of parameter “amount” with an explicit
Unmarshaller
Unmarshaller
as described in Unmarshalling - reject if the parameter is missing or can’t be unmarshalled to the given type
"distance".repeated
- extract multiple occurrences of parameter “distance” as
Iterable[String]
"distance".as[Int].repeated
- extract multiple occurrences of parameter “distance” as
Iterable[Int]
, you need a matchingUnmarshaller
Unmarshaller
in scope for that to work (see also Unmarshalling) "distance".as(unmarshaller).repeated
- extract multiple occurrences of parameter “distance” with an explicit
Unmarshaller
Unmarshaller
as described in Unmarshalling
You can use Case Class Extraction to group several extracted values together into a case-class instance.
In order to filter on the existence of several query parameters, you need to nest as many parameter directives as desired.
Query parameters can be either extracted as a String
or can be converted to another type. Different methods must be used when the desired parameter is required, optional or repeated.
Requests missing a required parameter or parameter value will be rejected with an appropriate rejection.
If an unmarshaller throws an exception while extracting the value of a parameter, the request will be rejected with a MissingQueryParameterRejection
if the unmarshaller threw an Unmarshaller.NoContentException
or a MalformedQueryParamRejection
MalformedQueryParamRejection
in all other cases. (see also Rejections)
There’s also a singular version, parameter. Form fields can be handled in a similar way, see formFields
.
See When to use which parameter directive? to understand when to use which directive.
Examples
Required parameter
- Scala
-
source
val route = parameters("color", "backgroundColor") { (color, backgroundColor) => complete(s"The color is '$color' and the background is '$backgroundColor'") } // tests: Get("/?color=blue&backgroundColor=red") ~> route ~> check { responseAs[String] shouldEqual "The color is 'blue' and the background is 'red'" } Get("/?color=blue") ~> Route.seal(route) ~> check { status shouldEqual StatusCodes.NotFound responseAs[String] shouldEqual "Request is missing required query parameter 'backgroundColor'" }
- Java
-
source
import static org.apache.pekko.http.javadsl.server.Directives.complete; import static org.apache.pekko.http.javadsl.server.Directives.parameter; final Route route = parameter( "color", color -> parameter( "backgroundColor", backgroundColor -> complete( "The color is '" + color + "' and the background is '" + backgroundColor + "'"))); // tests: testRoute(route) .run(HttpRequest.GET("/?color=blue&backgroundColor=red")) .assertEntity("The color is 'blue' and the background is 'red'"); testRoute(route) .run(HttpRequest.GET("/?color=blue")) .assertStatusCode(StatusCodes.NOT_FOUND) .assertEntity("Request is missing required query parameter 'backgroundColor'");
Optional parameter
- Scala
-
source
val route = parameters("color", "backgroundColor".optional) { (color, backgroundColor) => val backgroundStr = backgroundColor.getOrElse("<undefined>") complete(s"The color is '$color' and the background is '$backgroundStr'") } // tests: Get("/?color=blue&backgroundColor=red") ~> route ~> check { responseAs[String] shouldEqual "The color is 'blue' and the background is 'red'" } Get("/?color=blue") ~> route ~> check { responseAs[String] shouldEqual "The color is 'blue' and the background is '<undefined>'" }
- Java
-
source
import static org.apache.pekko.http.javadsl.server.Directives.complete; import static org.apache.pekko.http.javadsl.server.Directives.parameter; import static org.apache.pekko.http.javadsl.server.Directives.parameterOptional; final Route route = parameter( "color", color -> parameterOptional( "backgroundColor", backgroundColor -> complete( "The color is '" + color + "' and the background is '" + backgroundColor.orElse("undefined") + "'"))); // tests: testRoute(route) .run(HttpRequest.GET("/?color=blue&backgroundColor=red")) .assertEntity("The color is 'blue' and the background is 'red'"); testRoute(route) .run(HttpRequest.GET("/?color=blue")) .assertEntity("The color is 'blue' and the background is 'undefined'");
Optional parameter with default value
sourceval route =
parameters("color", "backgroundColor".withDefault("white")) { (color, backgroundColor) =>
complete(s"The color is '$color' and the background is '$backgroundColor'")
}
// tests:
Get("/?color=blue&backgroundColor=red") ~> route ~> check {
responseAs[String] shouldEqual "The color is 'blue' and the background is 'red'"
}
Get("/?color=blue") ~> route ~> check {
responseAs[String] shouldEqual "The color is 'blue' and the background is 'white'"
}
Parameter with required value
The requiredValue
decorator makes the route match only if the parameter contains the specified value. The directive parameterRequiredValue
makes the route match only if the parameter contains the specified value.
- Scala
-
source
val route = parameters("color", "action".requiredValue("true")) { (color, _) => complete(s"The color is '$color'.") } // tests: Get("/?color=blue&action=true") ~> route ~> check { responseAs[String] shouldEqual "The color is 'blue'." } Get("/?color=blue&action=false") ~> Route.seal(route) ~> check { status shouldEqual StatusCodes.NotFound responseAs[String] shouldEqual "Request is missing required value 'true' for query parameter 'action'" }
- Java
-
source
import static org.apache.pekko.http.javadsl.server.Directives.complete; import static org.apache.pekko.http.javadsl.server.Directives.parameterRequiredValue; final Route route = parameter( "color", color -> parameterRequiredValue( StringUnmarshallers.BOOLEAN, true, "action", () -> complete("The color is '" + color + "'."))); // tests: testRoute(route) .run(HttpRequest.GET("/?color=blue&action=true")) .assertStatusCode(StatusCodes.OK) .assertEntity("The color is 'blue'."); testRoute(route) .run(HttpRequest.GET("/?color=blue&action=false")) .assertStatusCode(StatusCodes.NOT_FOUND) .assertEntity("Request is missing required value 'true' for query parameter 'action'");
Deserialized parameter
- Scala
-
source
val route = parameters("color", "count".as[Int]) { (color, count) => complete(s"The color is '$color' and you have $count of it.") } // tests: Get("/?color=blue&count=42") ~> route ~> check { responseAs[String] shouldEqual "The color is 'blue' and you have 42 of it." } Get("/?color=blue&count=blub") ~> Route.seal(route) ~> check { status shouldEqual StatusCodes.BadRequest responseAs[String] shouldEqual "The query parameter 'count' was malformed:\n'blub'" + " is not a valid 32-bit signed integer value" }
- Java
-
source
import static org.apache.pekko.http.javadsl.server.Directives.complete; import static org.apache.pekko.http.javadsl.server.Directives.parameter; final Route route = parameter( "color", color -> parameter( StringUnmarshallers.INTEGER, "count", count -> complete( "The color is '" + color + "' and you have " + count + " of it."))); // tests: testRoute(route) .run(HttpRequest.GET("/?color=blue&count=42")) .assertEntity("The color is 'blue' and you have 42 of it."); testRoute(route) .run(HttpRequest.GET("/?color=blue&count=blub")) .assertStatusCode(StatusCodes.BAD_REQUEST) .assertEntity( "The query parameter 'count' was malformed:\n'blub'" + " is not a valid 32-bit signed integer value");
Repeated parameter
sourceval route =
parameters("color", "city".repeated) { (color, cities) =>
cities.toList match {
case Nil => complete(s"The color is '$color' and there are no cities.")
case city :: Nil => complete(s"The color is '$color' and the city is $city.")
case multiple => complete(s"The color is '$color' and the cities are ${multiple.mkString(", ")}.")
}
}
// tests:
Get("/?color=blue") ~> route ~> check {
responseAs[String] shouldEqual "The color is 'blue' and there are no cities."
}
Get("/?color=blue&city=Chicago") ~> Route.seal(route) ~> check {
responseAs[String] shouldEqual "The color is 'blue' and the city is Chicago."
}
Get("/?color=blue&city=Chicago&city=Boston") ~> Route.seal(route) ~> check {
responseAs[String] shouldEqual "The color is 'blue' and the cities are Boston, Chicago."
}
CSV parameter
sourceval route =
parameter("names".as(CsvSeq[String])) { names =>
complete(s"The parameters are ${names.mkString(", ")}")
}
// tests:
Get("/?names=") ~> route ~> check {
responseAs[String] shouldEqual "The parameters are "
}
Get("/?names=Caplin") ~> route ~> check {
responseAs[String] shouldEqual "The parameters are Caplin"
}
Get("/?names=Caplin,John") ~> route ~> check {
responseAs[String] shouldEqual "The parameters are Caplin, John"
}
Get("/?names=Caplin,John,") ~> route ~> check {
responseAs[String] shouldEqual "The parameters are Caplin, John, "
}
Repeated, deserialized parameter
sourceval route =
parameters("color", "distance".as[Int].repeated) { (color, distances) =>
distances.toList match {
case Nil => complete(s"The color is '$color' and there are no distances.")
case distance :: Nil => complete(s"The color is '$color' and the distance is $distance.")
case multiple => complete(s"The color is '$color' and the distances are ${multiple.mkString(", ")}.")
}
}
// tests:
Get("/?color=blue") ~> route ~> check {
responseAs[String] shouldEqual "The color is 'blue' and there are no distances."
}
Get("/?color=blue&distance=5") ~> Route.seal(route) ~> check {
responseAs[String] shouldEqual "The color is 'blue' and the distance is 5."
}
Get("/?color=blue&distance=5&distance=14") ~> Route.seal(route) ~> check {
responseAs[String] shouldEqual "The color is 'blue' and the distances are 14, 5."
}