§Routing DSL
Play provides a DSL for routers directly in code. 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.
The DSL uses a path pattern syntax similar to Play’s compiled routes files, extracting parameters out, and invoking actions implemented using lambdas.
The DSL is provided by RoutingDsl
. Since you will be implementing actions, you may want to import the static methods from Results
, which includes factory methods for creating results. The DSL gives you access to the current Http.Request and you can use it to access the session, cookies, etc. So typically you will want at least the following imports:
import javax.inject.Inject;
import play.api.mvc.AnyContent;
import play.api.mvc.BodyParser;
import play.api.mvc.PlayBodyParsers;
import play.core.j.JavaContextComponents;
import play.mvc.Http;
import play.routing.Router;
import play.routing.RoutingDsl;
import java.util.concurrent.CompletableFuture;
import static play.mvc.Controller.*;
And then you may use Dependency Injection to get a RoutingDsl
instance:
public class MyComponent {
private final RoutingDsl routingDsl;
@Inject
public MyComponent(RoutingDsl routing) {
this.routingDsl = routing;
}
}
Or you can directly create a new instance:
RoutingDsl routingDsl = new RoutingDsl(bodyParser, javaContextComponents);
A simple example of the DSL’s use is:
Router router = routingDsl
.GET("/hello/:to").routingTo( (request, to) ->
ok("Hello " + to)
)
.build();
The first parameter to the action block is an Http.Request. Then the :to
parameter is extracted out and passed as the first parameter to the router. Note that the name you give to parameters in the path pattern is irrelevant, the important thing is that parameters in the path are in the same order as parameters in your lambda. You can have anywhere from 0 to 3 parameters in the path pattern, and other HTTP methods, such as POST
, PUT
and DELETE
are supported.
Note: it is important to notice that when using the DSL, the first parameter will always be the
Http.Request
. The next parameters are the ones you actually declared at your route pattern.
Like Play’s compiled router, the DSL also supports matching multi path segment parameters, this is done by prefixing the parameter with *
:
Router router = routingDsl
.GET("/assets/*file").routingTo( (request, file) ->
ok("Serving " + file)
)
.build();
Regular expressions are also supported, by prefixing the parameter with a $
and post fixing the parameter with a regular expression in angled brackets:
Router router = routingDsl
.GET("/api/items/$id<[0-9]+>").routingTo( (request, id) ->
ok("Getting item " + id)
)
.build();
In the above examples, the type of the parameters in the lambdas is undeclared, which the Java compiler defaults to Object
. The routing DSL in this case will pass the parameters as String
, however if you define an explicit type on the parameter, the routing DSL will attempt to bind the parameter to that type:
Router router = routingDsl
.GET("/api/items/:id").routingTo((Http.Request request, Integer id) ->
ok("Getting item " + id)
)
.build();
Supported types include Integer
, Long
, Float
, Double
, Boolean
, and any type that extends PathBindable
.
Asynchronous actions are of course also supported, using the routingAsync
method:
Router router = routingDsl
.GET("/api/items/:id").routingAsync((Http.Request request, Integer id) ->
CompletableFuture.completedFuture(ok("Getting item " + id))
)
.build();
§Binding Routing DSL
Configuring an application to use a Routing DSL can be achieved in many ways, depending on use case:
§Embedding play
An example of embedding a play server with Routing DSL can be found in Embedding Play section.
§Providing a DI router
A router can be provided to the application similarly as detailed in Application Entry point and Providing a router, using e.g. a java builder class and an application loader:
public class AppLoader implements ApplicationLoader {
public Application load(ApplicationLoader.Context context) {
return new MyComponents(context).application();
}
}
class MyComponents extends RoutingDslComponentsFromContext
implements play.filters.components.NoHttpFiltersComponents {
MyComponents(ApplicationLoader.Context context) {
super(context);
}
@Override
public Router router() {
return routingDsl()
.GET("/hello/:to").routingTo((request, to) -> ok("Hello " + to))
.build();
}
}
§Providing a DI router with Guice
A router via Guice could be provided with the following snippet:
@Singleton
public class GuiceRouterProvider implements Provider<play.api.routing.Router> {
private final RoutingDsl routingDsl;
@Inject
public GuiceRouterProvider(RoutingDsl routingDsl) {
this.routingDsl = routingDsl;
}
@Override
public play.api.routing.Router get() {
return routingDsl
.GET("/hello/:to").routingTo((request, to) -> ok("Hello " + to))
.build()
.asScala();
}
}
and in the application loader:
public class GuiceAppLoader extends GuiceApplicationLoader {
@Override
protected GuiceableModule[] overrides(ApplicationLoader.Context context) {
GuiceableModule[] modules = super.overrides(context);
GuiceableModule module = GuiceableModule$.MODULE$.fromPlayBinding(new BindingKey<>(play.api.routing.Router.class).toProvider(GuiceRouterProvider.class).eagerly());
List<GuiceableModule> copyModules = new ArrayList<>(Arrays.asList(modules));
copyModules.add(module);
return copyModules.toArray(new GuiceableModule[copyModules.size()]);
}
}
§Overriding binding
A router can also be provided using e.g. GuiceApplicationBuilder
in the application loader to override with custom router binding or module as detailed in Bindings and Modules
Next: Custom Binding