Response
Constructors, header rules, cookies and what the server owns.
record Response {
var status: int = 200;
var headers: Headers;
var body: Bytes;
var closeConnection: bool = false;
}Constructors
jsonResponse(payload, status = 200)
htmlResponse(markup, status = 200)
textResponse(text, status = 200)
bytesResponse(payload, mime, status = 200)
redirect(location, status = 303)
noContent()
errorResponse(status, detail = "")errorResponse escapes detail, because it is a public parameter and a handler could pass request-derived text into it.
Headers the server owns
Content-Length, Date, Server and Connection are written at serialisation time and cannot be overridden by a handler. Every other header name and value is validated on the way out: CR, LF and NUL in a value are rejected, so a handler cannot inject a header or split a response. An invalid field is dropped and logged rather than emitted.
Cookies
response.setCookie("session", token, maxAge = 3600);setCookie defaults to HttpOnly, Secure, SameSite=Lax and Path=/, and percent-encodes the value. Those defaults are the safe ones; loosening them is an explicit argument at the call site, which is where such a decision should be visible.
Status codes from a page
Pages do not construct a Response. They set meta.status, and the generated handler builds the response around the rendered document:
meta.status = 404;That keeps a page's return type a plain string while still letting it answer honestly.
Redirects
proc get(ctx: Context): Response {
return redirect("/docs/introduction", 302);
}A route that only redirects is an API route, not a page โ it has no markup to render. This wiki uses exactly that for /docs, because a catch-all does not match its own parent path.