Filters and Errors
Filters
before/after take an optional path.
A trailing covers the prefix and everything under it, so /admin/ guards /admin as well as /admin/users, which is what a guard almost always means:
app.before("/admin/*", req -> req.sessionAttr("user") == null
? WebResponse.redirect("/login") // answers here, so the route handler never runs
: null); // carry on
A before-filter that returns a response ends the request there; returning null continues to the route.
To reject without a body of your own, throw new HttpException(HttpStatus.UNAUTHORIZED, "…") and let error(HttpStatus.UNAUTHORIZED, …) render it.
An after-filter takes the response the route returned and hands back a replacement, or null to leave it alone:
app.after((req, res) -> res.header("X-Request-Id", requestId()));
Error handlers
error(status, handler) fills in the body for any response that ended on that status with no body, whether from the router, from an HttpException, or from a handler that returned WebResponse.empty(HttpStatus.FORBIDDEN).
notFound(handler) is shorthand for error(HttpStatus.NOT_FOUND, handler), so one registration styles the router’s own 404 and every handler-made one alike.
A response that already carries a body is left alone.
What the error handler returns keeps the headers the framework had already worked out, such as the Allow of a 405, and answers with the registered status unless it sets one of its own.
Inside an error handler, req.errorMessage() is the plain-text message the framework would have used.