Skip to content
English

Request ID

requestId() gives every request a stable id — for log correlation and to pass downstream. It forwards the id to the handler (via the enriched request) and echoes it on the response.

import { requestId, withMiddleware } from 'actor-ts/http';
const routes = withMiddleware(requestId(), appRoutes);
// in a handler:
get((req) => completeJson(Status.OK, { id: req.headers['x-request-id'] }));

An incoming id is accepted only if it is well-formed (^[A-Za-z0-9._-]{1,64}$) — a hostile value never reaches a response header; otherwise a fresh id is generated with randomUuid.

A short-circuit that throws is echoed too: the 401 or 403 an auth or CSRF layer below throws comes back carrying the id, which is exactly the response whose log line someone will later go looking for. An unhandled throw is the exception — it maps to the generic 500, which deliberately carries nothing from the thrown value, so that one arrives without an id.

requestIdOf(request) returns the id the request carries, or undefined when it carries none — or when what it carries fails the same shape check. Prefer it over a raw header read anywhere the value reaches a log line: a client-controlled string can forge whole log records through an embedded newline, and the check is what stops it.

import { requestIdOf } from 'actor-ts/http';
system.log.error(`[http] ${req.method} ${req.path} (${requestIdOf(req) ?? '-'})`, err);

It reports what the request claimed, so under trustIncoming: false — where the middleware substitutes its own id downstream — name the header rather than presenting the value as the id. Pass the header name as a second argument if you renamed it.

Builder methodFieldDefault
withHeaderName(n)headerName'x-request-id'
withTrustIncoming(flag?)trustIncomingtrue
withGenerate(generate)generaterandomUuid