Compared with Play routes
If you have been using Play’s routes file syntaxPlay’s routes file syntax earlier, this page may help you to use the Apache Pekko HTTP routing DSL.
Conceptual differences
The most apparent difference is Play’s use of special purpose syntax implemented as an external DSL, whereas Apache Pekko HTTP routes are described in Scala source codeJava source code with regular methods and values (as “embedded DSL”). Both are crafted to make the reader “grasp the code’s intention”.
The Apache Pekko HTTP DSL uses Directives to describe how incoming requests translate to functionality in the server. Play allows splitting the routes definitions in multiple routes files. The Apache Pekko HTTP DSL is very flexible and allows for composition so that different concerns can be properly split and organized as other source code would be.
Both Play and Apache Pekko HTTP choose the first matching route within the routes file/routes definition. In Play routes are listed with one route per line, in Apache Pekko HTTP multiple routes must be concatenated with the concat
method.
Side-by-side
These examples are a non-comprehensive list of how Play routes could be written in Apache Pekko HTTP. They try to mimic the structure which Play uses, to aid understanding, even though it might not be the most Apache Pekko HTTP-idiomatic notation.
Static path
For example, to exactly match incoming GET /clients/all
requests, you can define this route in Play.
GET /clients/all controllers.Clients.list()
In Apache Pekko HTTP every path segment is specified as a separate String
concatenated with the /
methodconcatenated by the slash
method on segment
.
- Scala
-
source
(get & path("clients" / "all")) { complete(Clients.list()) }
- Scala test
-
source
Get("/clients/all") ~> clientsAll ~> check { responseAs[String] shouldEqual "clientA,clientB,clientC" }
- Java
-
source
get(() -> path(segment("clients").slash("all"), () -> complete(Clients.list())));
- Java test
-
source
TestRoute route = testRoute(new Routes().clientsAll()); route .run(HttpRequest.GET("/clients/all")) .assertStatusCode(StatusCodes.OK) .assertEntity("clientA,clientB,clientC");
Dynamic parts
If you want to define a route that retrieves a client by ID, you’ll need to add a dynamic part.
GET /clients/:id controllers.Clients.show(id: Long)
Apache Pekko HTTP uses path matchers which match certain data types and pass their data on.
- Scala
-
source
(get & path("client" / LongNumber)) { id => complete(Clients.get(id)) }
- Scala test
-
source
Get("/client/321433") ~> clientById ~> check { responseAs[String] shouldEqual "clientB" }
- Java
-
source
get(() -> path(segment("client").slash(longSegment()), id -> complete(Clients.get(id))));
- Java test
-
source
TestRoute route = testRoute(new Routes().clientById()); route .run(HttpRequest.GET("/client/321433")) .assertStatusCode(StatusCodes.OK) .assertEntity("clientB");
Dynamic parts spanning several /
You may want to capture a dynamic part of more than one URI path segment, separated by forward slashes.
GET /files/*name controllers.Application.download(name)
The Apache Pekko HTTP directive Remaining
remaining() makes a list of the segments to be passed. (See Path Matchers for other ways to extract the path.)
- Scala
-
source
(get & path("files" / Remaining)) { name => complete(download(name)) }
- Scala test
-
source
Get("/files/images/logo.png") ~> files ~> check { responseAs[String] shouldEqual "images/logo.png: file contents" }
- Java
-
source
get(() -> path(segment("files").slash(remaining()), names -> complete(download(names))));
- Java test
-
source
TestRoute route = testRoute(new Routes().files()); route .run(HttpRequest.GET("/files/images/logo.png")) .assertStatusCode(StatusCodes.OK) .assertEntity("images/logo.png: file contents");
Access parameters
The Parameter directives give access to parameters passed on the URL.
Mandatory parameters
By default parameters are expected to be of type String
. To make Apache Pekko HTTP convert a parameter to a different type, specify an unmarshaller.
# Extract the page parameter from the query string.
# i.e. http://myserver.com/?page=index
GET / controllers.Application.show(page)
- Scala
-
source
(get & path("") & parameter("page")) { page => complete(getPage(page)) }
- Scala test
-
source
Get("/?page=example.txt") ~> pageParameter ~> check { responseAs[String] shouldEqual "The requested [example.txt]." }
- Java
-
source
get(() -> parameter("page", page -> complete(getPage(page))));
- Java test
-
source
TestRoute route = testRoute(new Routes().pageParameter()); route .run(HttpRequest.GET("?page=example.txt")) .assertStatusCode(StatusCodes.OK) .assertEntity("The requested [example.txt]."); route.run(HttpRequest.GET("/")).assertStatusCode(StatusCodes.NOT_FOUND);
Optional parameters
# The version parameter is optional. E.g. /api/list-all?version=3.0
GET /api/list-all controllers.Api.list(version: Option[String])
The parameter name may be decorated with .optional
to mark it as optional (for other variants see other parameter extractors).
The parameterOptional
directive passes the parameter as Optional<String>
.
The directive parameterRequiredValue
makes the route match only if the parameter contains the specified value.
See parameter extractors.
- Scala
-
source
(get & path("api" / "list-all") & parameter("version".optional)) { version => complete(listAll(version)) }
- Scala test
-
source
Get("/api/list-all?version=3.0") ~> optionalPageParameter ~> check { responseAs[String] shouldEqual "aa,bb,cc" } Get("/api/list-all") ~> optionalPageParameter ~> check { responseAs[String] shouldEqual "ff" }
- Java
-
source
get( () -> path( segment("api").slash("list"), () -> parameterOptional("version", version -> complete(apiList(version)))));
- Java test
-
source
TestRoute route = testRoute(new Routes().apiListWithVersion()); route .run(HttpRequest.GET("/api/list?version=3.0")) .assertStatusCode(StatusCodes.OK) .assertEntity("aa,bb,cc"); route.run(HttpRequest.GET("/api/list")).assertStatusCode(StatusCodes.OK).assertEntity("ff");
List parameters
This shows how a repeated URL parameter is captured.
# The item parameter is a list.
# E.g. /api/list-items?item=red&item=new&item=slippers
GET /api/list-items controllers.Api.listItems(item: List[String])
Decorating the parameter name with a .repeated
makes Apache Pekko HTTP pass all values of that parameter as an Iterable[String]
].
The parameterList
directive may take a parameter name to specify a single parameter name to pass on as a List<String>
.]
- Scala
-
source
(get & path("api" / "list-items") & parameters("item".repeated)) { items => complete(listItems(items)) }
- Scala test
-
source
Get("/api/list-items?item=red&item=new&item=slippers") ~> itemParameterList ~> check { responseAs[String] shouldEqual "slippers,new,red" }
- Java
-
source
get( () -> path( segment("api").slash("list-items"), () -> parameterList("item", items -> complete(apiItems(items)))));
- Java test
-
source
TestRoute route = testRoute(new Routes().apiListItems()); route .run(HttpRequest.GET("/api/list-items?item=red&item=new&item=slippers")) .assertStatusCode(StatusCodes.OK) .assertEntity("slippers,new,red"); // order is not kept