Handlers

Handler has a single method, so the application decides what shape a handler takes. The example app uses all three shapes: a lambda, an Action class, and public methods registered by reference.

A lambda

Use a lambda when there is no state worth a class:

app.get("/openapi.json", req -> {
    JsonValue resBody = OpenApi.document("Flashcard API", "1.0.0", app.routes());
    return WebResponse.json(resBody);
});

An Action class

Use a class for a handler that answers exactly one route. The class implements Handler, so an instance registers directly:

public class StatsAction implements Handler {

    private final StatsService statsService;

    public StatsAction(StatsService statsService) {
        this.statsService = statsService;
    }

    @Override
    public WebResponse handle(WebRequest req) {
        return WebResponse.template("stats", Model.of("stats", statsService.overview()));
    }
}
app.get("/stats", statsAction);

Action is the A of the ADR (Action-Domain-Responder) pattern: a web-tier class that answers exactly one request. Laravel’s single action controllers follow the same convention. The framework does not know the name. Handler is the interface, and …Action is a naming convention for the classes that implement it directly.

Public methods, registered by reference

Register methods by reference when one class answers several related routes:

public class DeckController {

    public WebResponse showDeck(WebRequest req) { ... }

    public WebResponse renameDeck(WebRequest req) { ... }
}
app.get("/decks/{deckId}", deckController::showDeck);
app.post("/decks/{deckId}/rename", deckController::renameDeck);

The methods are public because registration deliberately happens outside the class. There is no Controller interface and no register(App) method to implement. Every route the application answers is therefore one statement in one list, and app.routes() reports exactly what is written there. A class that registers its own routes hides half the routing table inside itself, which is what annotation scanning does, spelled out by hand.