Controllers

All your controllers must extend BaseController and be annotated with @Controller.

Basic controller
@Controller
public class ArticleController extends BaseController {

    @GET(value = "/articles", name = "articles.index")
    private Object index(Request req, Response res) {
        return render("articles/index.html", Map.of(
            "title", "My articles"
        ));
    }

    @POST(value = "/articles", name = "articles.store")
    private Object store(Request req, Response res) {
        String title = req.queryParams("title");

        Article article = new Article();
        article.set("title", title);
        article.saveIt();

        res.redirect("/articles");
        return null;
    }
}
Dependency injection

Two ways to inject a @Repository into a controller.

Field injection — available across all methods
@Controller
public class ArticleController extends BaseController {

    @Inject
    private ArticleRepository articleRepo;

    @GET(value = "/articles", name = "articles.index")
    private Object index(Request req, Response res) {
        List<Article> articles = articleRepo.findAll().stream().toList();
        return render("articles/index.html", Map.of("articles", articles));
    }

    @DELETE(value = "/articles/:id", name = "articles.delete")
    private Object delete(Request req, Response res) {
        articleRepo.delete(req.params(":id"));
        res.redirect("/articles");
        return null;
    }
}
Method parameter — useful when only one route needs it
@GET(value = "/articles", name = "articles.index")
private Object index(Request req, Response res, ArticleRepository articleRepo) {
    List<Article> articles = articleRepo.findAll().stream().toList();
    return render("articles/index.html", Map.of("articles", articles));
}
💡 Tip

Prefer @Inject when you use the same repository in multiple methods. Use method parameters for one-off injections to keep things explicit.