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 matching UnmarshallerUnmarshaller 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 UnmarshallerUnmarshaller 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 matching UnmarshallerUnmarshaller in scope for that to work (see also Unmarshalling)
"distance".as(unmarshaller).repeated
extract multiple occurrences of parameter “distance” with an explicit UnmarshallerUnmarshaller 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 MalformedQueryParamRejectionMalformedQueryParamRejection 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
sourceval 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
sourceimport 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
sourceval 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
sourceimport 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
sourceval 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
sourceimport 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
sourceval 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
sourceimport 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."
}