Context
The request, the parameters, and nothing below them.
Context is what a handler sees: no file descriptors, no buffers, no C pointers.
record Context {
var request: Request;
var params: map(string, string);
var locals: map(string, string);
var startedAtMillis: int(64);
var requestId: string;
}Methods
| Member | Returns |
|---|---|
pathParam(name, fallback = "") | A captured route segment |
paramInt(name, fallback) | The same, parsed as an integer |
queryParam(name, fallback = "") | A query-string value |
setLocal(name, value) | Stores per-request scratch state |
getLocal(name, fallback = "") | Reads it back |
method() | The request method |
path() | The normalised request path |
The request
ctx.request.header("Accept") // one header, with a fallback
ctx.request.contentType()
ctx.request.bodyText()
ctx.request.accepts("application/json")
ctx.request.clientIp()
ctx.request.query.get("q")
ctx.request.query.getInt("page", 1)
ctx.request.peerIp
ctx.request.peerPortQuery parameters are decoded with + as a space, and repeated keys keep the first value. getInt returns its fallback rather than throwing when a value is missing or unparsable, which is what makes ?page=banana a page-one request instead of a 500.
Reading cookies
There is no cookie map: read the header and parse what you need. Bound the header, then map the value onto an enum rather than carrying it around as a string:
enum Density { comfortable, compact }
proc densityFrom(header: string): Density {
if header.isEmpty() || header.numBytes > 4096 then return Density.comfortable;
for pair in header.split(";") {
const entry = trim(pair);
const eq = idx(entry, "=");
if eq <= 0 then continue;
if trim(sub(entry, 0, eq)) != "density" then continue;
return if foldAscii(trim(sub(entry, eq + 1, entry.numBytes))) == "compact"
then Density.compact else Density.comfortable;
}
return Density.comfortable;
}The value never reaches the markup as a string. It becomes an enum, and the enum picks a class name from a fixed set — so a hostile cookie has nowhere to go.
Concurrency
Route handlers run concurrently on different tasks, each with its own Context. Module-level state must be immutable after start-up, or guarded — see concurrency.