Play’s default routes generator creates a router class that accepts controller instances in an @Inject-annotated constructor. That means the class is suitable for use with dependency injection and can also be instantiated manually using the constructor.

Play also comes with a legacy static routes generator that works with controllers declared as objects. This is generally not recommended because it breaks encapsulation, makes code less testable, and is incompatible with many of Play’s new APIs.

If you need to use static controllers, you can switch to the static routes generator by adding the following configuration to your build.sbt.

routesGenerator := StaticRoutesGenerator

The code samples in Play’s documentation assumes that you are using the injected routes generator. If you are not using this, you can trivially adapt the code samples for the static routes generator, either by prefixing the controller invocation part of the route with an @ symbol, or by declaring each of your controllers as an object rather than a class.

conf/routes is the configuration file used by the router. This file lists all of the routes needed by the application. Each route consists of an HTTP method and URI pattern, both associated with a call to an Action generator.

Let’s see what a route definition looks like:

GET /clients/:id controllers.Clients.show(id: Long)

Each route starts with the HTTP method, followed by the URI pattern. The last element is the call definition.

It is also possible to apply modifiers by preceding the route with a line starting with a +. This can change the behavior of certain Play components. One such modifier is the “nocsrf” modifier to bypass the CSRF filter:

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)

Note: A URI pattern may have more than one dynamic part.

The default matching strategy for a dynamic part is defined by the regular expression [^/]+, meaning that any dynamic part defined as :id will match exactly one URI path segment. Unlike other pattern types, path segments are automatically URI-decoded in the route, before being passed to your controller, and encoded in the reverse route.

If you want a dynamic part to capture more than one URI path segment, separated by forward slashes, you can define a dynamic part using the *id syntax, also known as a wildcard pattern, which uses the .* regular expression:

GET /files/*name controllers.Application.download(name)

Here for a request like GET /files/images/logo.png, the name dynamic part will capture the images/logo.png value.

Note that dynamic parts spanning several / are not decoded by the router or encoded by the reverse router. It is your responsibility to validate the raw URI segment as you would for any user input. The reverse router simply does a string concatenation, so you will need to make sure the resulting path is valid, and does not, for example, contain multiple leading slashes or non-ASCII characters.

The router can also be used to generate a URL from within a Scala call. This makes it possible to centralize all your URI patterns in a single configuration file, so you can be more confident when refactoring your application.

For each controller used in the routes file, the router will generate a ‘reverse controller’ in the routes package, having the same action methods, with the same signature, but returning a play.api.mvc.Call instead of a play.api.mvc.Action.

The play.api.mvc.Call defines an HTTP call, and provides both the HTTP method and the URI.

Note: There is a routes subpackage for each controller package. So the action controllers.Application.hello can be reversed via controllers.routes.Application.hello (as long as there is no other route before it in the routes file that happens to match the generated path).

The reverse action method works quite simply: it takes your parameters and substitutes them back into the route pattern. In the case of path segments (:foo), the value is encoded before the substitution is done. For regex and wildcard patterns the string is substituted in raw form, since the value may span multiple segments. Make sure you escape those components as desired when passing them to the reverse route, and avoid passing unvalidated user input.

There are instances where returning a relative route instead of an absolute may be useful. The routes returned by play.mvc.Call are always absolute (they lead with a /), which can lead to problems when requests to your web application are rewritten by HTTP proxies, load balancers, and API gateways. Some examples where using a relative route would be useful include:

Hosting an app behind a web gateway that prefixes all routes with something other than what is configured in your conf/routes file, and roots your application at a route it’s not expecting.

When dynamically rendering stylesheets, you need asset links to be relative because they may end up getting served from different URLs by a CDN.

To be able to generate a relative route you need to know what to make the target route relative to (the start route). The start route can be retrieved from the current RequestHeader. Therefore, to generate a relative route it’s required that you pass in your current RequestHeader or the start route as a String parameter.

Play includes a Default controller which provides a handful of useful actions. These can be invoked directly from the routes file:

# Redirects to https://www.playframework.com/ with 303 See Other
GET /about controllers.Default.redirect(to = "https://www.playframework.com/")
# Responds with 404 Not Found
GET /orders controllers.Default.notFound
# Responds with 500 Internal Server Error
GET /clients controllers.Default.error
# Responds with 501 Not Implemented
GET /posts controllers.Default.todo

In this example, GET /about redirects to an external website, but it’s also possible to redirect to another action (such as /posts in the above example).

Play provides a DSL for defining embedded routers called the String Interpolating Routing DSL, or sird for short. This DSL has many uses, including embedding a light weight Play server, providing custom or more advanced routing capabilities to a regular Play application, and mocking REST services for testing.