The Request

Cookies

Cookies split along the same line the rest of the API does: the ones the client sent are read off the request, the ones the server sets are part of the response.

String theme = req.cookie("theme");         // null when absent
Map<String, String> all = req.cookies();    // a repeated name keeps the first value

Setting one is the response’s side — WebResponse.cookie(…​), with the defaults The Response describes.

Repeated parameters

List<String> tags = req.params("tag");      // ?tag=java&tag=web, or a checkbox group

params(name) returns every value in request order, and an empty list when the parameter is absent: "no boxes checked" is an answer, not a 400. param(name) still returns the first value and still 400s when there is none. For an optional parameter with a type, paramLong("page", 1) and paramEnum("direction", Direction.class, Direction.FRONT) answer the default when the parameter is absent, and still 400 when it is present but unparseable, because the default covers absence, not garbage.

Query string vs. form body

The servlet API merges the two, so param("id") answers to an id in the URL and an id in the form alike. When the difference matters, say which one:

String page = req.queryParam("page");     // query string only, null when absent
String name = req.formParam("name");      // form body only
List<String> tags = req.formParams("tag");

File uploads

req.file(name) reads a file out of a multipart form, answering 400 when the part is missing and 400 when the request is not multipart at all:

app.post("/decks/{deckId}/import", req -> {
    UploadedFile file = req.file("file");
    int imported = deckService.importCsv(req.pathParamLong("deckId"), file.asText());
    req.flash("message", "Imported " + imported + " cards.");
    return WebResponse.redirect("/decks/" + req.pathParam("deckId"), HttpStatus.SEE_OTHER);
});

UploadedFile answers fileName(), contentType(), size(), and the content as bytes() or as UTF-8 text with asText(). The limits — maximum sizes, and where a large upload is buffered — are the servlet container’s multipart configuration, set on the server: multipart(new MultipartConfigElement(…​)) on JettyServer, TomcatServer, and UndertowServer alike. The default buffers to the system temp directory with no size cap and a 1MB in-memory threshold; multipart(null) turns multipart handling off.