Fork me on GitHub

A filter can be any regular Route that doesn’t commit the response.

For example we can create an AuditFilter (a before filter) with this code:

// audit filter
ANY("/.*", routeContext -> {
    log.info("Request for {} '{}'", routeContext.getRequestMethod(), routeContext.getRequestUri());
    routeContext.next();
});

In above snippet we added a before filter on all requests, this filter logs the request method and the request URI.
At the end of the filter we MUST call routeContext.next() to jump to the next route/filter from the chain.

Note: If you want to add a filter for all routes you MUST use /.* and NOT /*:

Another before filter can be an AuthenticationFilter:

// authentication filter
GET("/contact.*", routeContext {
    if (routeContext.getSession("username") == null) {
        routeContext.redirect("/login");
    } else {
        routeContext.next();
    }
});

In above snippet we protected all contact pages. If the current session doesn’t contain an attribute username then our filter redirects the request to the login page.

Now for a complicated scenario where we are getting a Database instance to be shared throughout a request-response cycle:

// before filter that create a database instance
ANY("/.*", routeContext -> {
    routeContext.setLocal("database", getDatabase());
    routeContext.next();
}); 

// insert data in database
POST("/{id}", routeContext -> {
    Database database = routeContext.getLocal("database");
    database.insert(something); // this line can throws an error
});

// after filter that release the database instance
ANY("/.*", routeContext -> {
    Database database = routeContext.removeLocal("database");
    database.release();
}).runAsFinally(); 

Please notice that we must mark the last filter with runAsFinally that are guaranteed to execute at the end of the Request-Response cycle despite exceptions within the chain.