API routes
Method handlers, request bodies, responses and status codes.
A module that exports procedures named for HTTP methods is an API route. The handler names are get, post, put, patch, del and options.
del serves DELETE because delete is a Chapel keyword and cannot name a procedure. Writing proc delete is reported by the scanner with that explanation rather than left to chpl to complain about in less obvious terms.
HEAD is served by the GET handler with the body elided at write time.
module ApiTasks {
use Cataract;
use TaskStore;
proc get(ctx: Context): Response {
var body = new JsonBuilder();
body.beginObject();
body.field("count", TaskStore.count());
body.endObject();
return jsonResponse(body.done());
}
proc post(ctx: Context): Response throws {
const title = JsonField.text(ctx.request.bodyText(), "title");
if title.isEmpty() then return errorResponse(422, "title is required");
var response = jsonResponse(TaskStore.add(title), 201);
response.setHeader("Location", "/tasks/" + TaskStore.count():string);
return response;
}
}Throwing handlers
A handler declared throws is wrapped by the generated dispatcher: an escaped error is logged and becomes a 500 rather than unwinding the connection task and taking the connection with it.
Response constructors
jsonResponse(payload, status = 200)
htmlResponse(markup, status = 200)
textResponse(text, status = 200)
bytesResponse(payload, mime, status = 200)
redirect(location, status = 303)
noContent() // 204
errorResponse(status, detail = "") // a minimal HTML error document| Method | Effect |
|---|---|
setHeader(name, value) | Replaces any existing value |
addHeader(name, value) | Appends, for multi-value fields |
setBody(text) | Replaces the body |
setCookie(name, value, ...) | Appends a Set-Cookie |
Content-Length, Date, Server and Connection are written by the server and cannot be overridden. Header names and values are validated at write time, so a handler cannot inject a header or split a response.
Request bodies
Bodies are available as ctx.request.bodyText() or as raw bytes through ctx.request.body, and are bounded by server.max_body_bytes. A larger body is rejected with 413 before any handler runs.
A POST, PUT or PATCH carrying neither Content-Length nor Transfer-Encoding is rejected with 411, before routing. Chunked bodies are decoded; trailers are consumed and discarded rather than merged into the headers.
Headless projects
A project with no pages needs no app/layouts, and its 404 and 405 responses are JSON rather than HTML โ an application with no HTML surface should not answer with markup.