Skip to main content
Every controller receives a context, and the incoming HTTP request lives on context.request. It is an HttpRequest instance (implementing the IRequest interface) that wraps the native Request and exposes the parsed pieces you actually need: the URL, the method, the headers, the query string, the route params, the decoded body, the client IP, the detected locale, and any uploaded files. The framework builds it from the native request before the controller runs, so you never construct one by hand. You read it. For the values you reach for most, the context also carries convenience accessors that point straight at the request: context.params, context.queries, and context.payload are the same objects as context.request.params, context.request.queries, and context.request.payload.

What the request object holds

The native Request gives you a raw URL string and a Headers bag. IRequest hands you a parsed IUrl, a typed queries record, route params, and the decoded payload, so you don’t re-parse in every controller. The interface is generic over params, payload, and queries, so a controller declares the exact shape it expects through IRequest<Config> and reads it with full typing. The headers come decoded too: request.header is a Header object with helpers for content type, auth, cookies, and IP, plus a parsed userAgent. The request resolves a lang from the query string, a custom header, or Accept-Language, so locale is ready for translation without extra work. Multipart uploads are parsed into IRequestFile instances on request.files, each one exposing size, type, format detection, read methods, and a write to disk.

How it works

The framework reads the native Request, extracts route params from the matched route and the decoded body, then constructs the HttpRequest. During construction it parses the URL (path, host, queries), normalizes the method, wraps the headers, parses the user agent, builds a RequestFile for every uploaded file, and resolves the locale.

Properties and methods

context.request exposes these read-only members:

Reading query and route params

Route params come from the dynamic segments of the matched route (/users/:id). Query params come from the URL query string (?page=2&search=alice). Read them from the request, or from the context.params / context.queries shortcuts.

Reading the payload

For POST, PUT, and PATCH requests the decoded body is on payload (and mirrored on context.payload). For JSON requests it is the parsed object; for form submissions it is the field record.
Type the payload at the controller level so reads are checked:
Validate the payload before trusting it. See Validation.

Headers and user agent

request.header is a Header object. Use get(name) and has(name) for raw values, or the typed convenience getters for common headers.
The user agent is parsed once during construction into an IUserAgent with browser, engine, os, device, and cpu. It is null when no User-Agent header is present.

File uploads

When the request is multipart form data, the framework parses it into request.form (the raw FormData) and request.files, a record keyed by form field name where each value is an IRequestFile. A RequestFile wraps the native File and adds metadata, format detection, read methods, and disk writing.

RequestFile API

For organizing uploads, derived paths, and storage backends, see Storage.

Language and locale detection

Every request resolves a lang ({ code, region }) during construction, with a fixed precedence: When the locale comes from a query param or the custom header, region is null and only code is set. When it falls back to Accept-Language, the first language is parsed into code and region (e.g. { code: "en", region: "US" }). If nothing matches, it defaults to en-US.

Reading the request well

For everyday access, read context.params, context.queries, and context.payload; reach for context.request when you need headers, IP, files, or locale. Declare a Config for IRequest<Config> (or cast) so those members are checked rather than typed any. Query and body values are user input, so run them through Validation before acting on them. Treat the request as read-only. Every member of IRequest is immutable, so build your reply on context.response instead of changing the request. When you save an upload, use file.name, the generated collision-safe name, not the user-supplied originalName, and check size and the is* flags first. For locale, read request.lang rather than re-parsing Accept-Language yourself; it already applies the documented precedence.
  • Controllers: where the request reaches your handler via context.
  • Validation: validate params, queries, and payload before use.
  • Response: build the reply with context.response.
  • Storage: persist uploaded files beyond a single request.