play framework route that matches all

All we need is an easy explanation of the problem, so here it is.

I’m working on an angular app using play framework for my rest-services. Everything in the public folder is an angular app (stylesheets, javascripts, images and html). I want every request that is not for something in the stylesheets, javascripts, templates or images folder to be routed to the index.html page. This is so that angular routing can take over from there…

As a side note i can mention that I am going to place every restservice under /services/ which links to my own java controllers.

Is it possible in play framework 2.3.4 to define a route that catches all without having to use the matching elements?

This is my route defs so far:

GET     /                       controllers.Assets.at(path="/public", file="index.html")
GET     /stylesheets/*file      controllers.Assets.at(path="/public/stylesheets", file)
GET     /javascripts/*file      controllers.Assets.at(path="/public/javascripts", file)
GET     /templates/*file        controllers.Assets.at(path="/public/templates", file)
GET     /images/*file           controllers.Assets.at(path="/public/images", file)

#this line fails
GET     /*                      controllers.Assets.at(path="/public", file="index.html")

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

It’s not possible to omit usage of matching elements but you can route a client via controller. The route definition looks like this:

GET         /*path               controllers.Application.matchAll(path)

And the corresponding controller can be implemented as follows:

public class Application extends Controller {

    public static Result matchAll(String path) {
        return redirect(controllers.routes.Assets.at("index.html"));
    }

}

Update

If you don’t want to redirect a client you can return a static resource as a stream. In this case a response MIME type is required.

public class Application extends Controller {

    public static Result matchAll(String path) {
        return ok(Application.class.getResourceAsStream("/public/index.html")).as("text/html");
    }

}

Method 2

For this task you can use onHandlerNotFound in Global class which will render some page without redirect:

import play.*;
import play.mvc.*;
import play.mvc.Http.*;
import play.libs.F.*;

import static play.mvc.Results.*;

public class Global extends GlobalSettings {

    public Promise<Result> onHandlerNotFound(RequestHeader request) {
        return Promise.<Result>pure(notFound(
            views.html.notFoundPage.render(request.uri())
        ));
    }

}

Method 3

Answer for scala developers using playframework 🙂

Similar to above one about creating controller which will accept parameters and then omit them.

Example routing:

GET     /               controllers.Assets.at(path="/public", file="index.html")
GET     /*ignoredPath   ui.controller.AssetsWithIgnoredWildcard.at(path="/public", file="index.html", ignoredPath: String)

controller with assets injected by framework:

class AssetsWithIgnoredWildcard @Inject() (assets: Assets) {
  def at(
      path: String,
      file: String,
      wildcardValueToIgnore: String, 
      aggressiveCaching: Boolean = false): Action[AnyContent] = {
    assets.at(path, file, aggressiveCaching)
  }
}

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply