Skip to Content

Request context

The object that describes the request in flight.

Every request gets one RequestContext. Middlewares and error handlers receive it, handlers get it as ctx, and scoped services can inject it.

MemberValue
requestThe Fetch Request.
method, headersShortcuts to the request's.
urlA parsed URL, created on first use.
queryThe query string as an object. Repeated keys become arrays.
paramsRaw route parameters, decoded.
route{ method, path, name, meta }, or undefined when nothing matched.
remoteAddressThe peer's IP address from the adapter. Behind a proxy, the proxy's.
providerThe request's DI scope.
body()The parsed body, read once and cached.
cookiesget, has, all for the request; set, delete for the response.
setHeader(name, value), responseHeadersHeaders to add to the response.
set(key, value), get(key)A per-request state bag.

See handlers for worked examples of each.

Injecting it

@Service({ lifetime: 'scoped' })
export class CurrentUser {
  readonly id: string | undefined;

  constructor(ctx: RequestContext) {
    this.id = ctx.headers.get('x-user-id') ?? undefined;
  }
}

route.get('/me', {
  services: { user: CurrentUser },
  handle: ({ user }) => ({ id: user.id }),
});

Only scoped and transient services can inject the context. A singleton that tries is a captive dependency, and Suku refuses to start.

Sharing state

const authenticate = middleware(async (ctx, next) => {
  ctx.set('user', await verify(ctx.headers.get('authorization')));
  return next();
});

route.get('/me', { middlewares: [authenticate], handle: ({ ctx }) => ctx.get<User>('user') });

The body

A route with a body schema receives the validated body. Without one, body is undefined and nothing is read. Call ctx.body() to parse it yourself; the result is cached, so a middleware and a handler share one read.

Content typeResult
application/json, *+jsonThe parsed value. Malformed JSON is a 400.
application/x-www-form-urlencodedAn object. Repeated keys become arrays.
multipart/form-dataA FormData.
text/*, or noneA string.
Anything elseA Uint8Array.

Bodies over the limit get 413. The limit is 1 MiB unless set.

await Suku.create({ features: [AppFeature], bodyLimit: 5 * 1024 * 1024 });

On this page