Skip to main content
zerotal

Documentation


Documentation / zerotal / index / HttpContext

Class: HttpContext<TParams>

Defined in: packages/core/src/pipeline/HttpContext.ts:66

The central per-request object, exposing request input, response helpers, route-model bindings, session flash, and after-response hooks to controllers and middleware.

Lives in the AsyncLocalStorage store AND travels through the pipeline. Both are the same object reference — no sync needed between them.

Examples

// A controller action reading input and returning JSON:
async show(ctx: HttpContext) {
  const id = ctx.integer('id');
  const post = ctx.model<Post>('post');
  return ctx.json({ id, post });
}
// An inline route handler — the context is passed directly:
Router.post('/subscribe', async (ctx) => {
  const { email } = await ctx.body<{ email: string }>();
  ctx.flash('success', `Subscribed ${email}`);
  ctx.redirect('/thanks', 303);
});

Type Parameters

TParams

TParams extends Record<string, unknown> = Record<string, string>

Shape of ctx.params (route params plus resolved model bindings). Defaults to a string-keyed record.

Constructors

Constructor

new HttpContext<TParams>(request, container): HttpContext<TParams>

Defined in: packages/core/src/pipeline/HttpContext.ts:129

Parameters

request

Request

container

ScopedResolver

Returns

HttpContext<TParams>

Files & uploads

file()

file(field): Promise<UploadedFile | null>

Defined in: packages/core/src/pipeline/HttpContext.ts:638

Return the first uploaded file for the given form field, or null if absent.

Parses and caches the multipart body on first call.

Parameters

field

string

Returns

Promise<UploadedFile | null>

Example

const avatar = await ctx.file('avatar');
if (!avatar?.isValid({ maxSize: 2 * 1024 * 1024, mimes: ['image/jpeg', 'image/png'] })) {
  return redirect().back().withErrors({ avatar: 'Invalid file.' });
}
const path = await avatar.store('avatars', Storage.disk());

files()

files(field): Promise<UploadedFile[]>

Defined in: packages/core/src/pipeline/HttpContext.ts:657

Return all uploaded files for the given form field. Useful for <input type="file" multiple> inputs.

Parameters

field

string

Returns

Promise<UploadedFile[]>

Example

const attachments = await ctx.files('attachments');
for (const file of attachments) {
  await file.store('attachments', Storage.disk('s3'));
}

Lifecycle

took

Get Signature

get took(): number

Defined in: packages/core/src/pipeline/HttpContext.ts:153

Elapsed milliseconds since this request started.

Returns

number


afterResponse()

afterResponse(callback): this

Defined in: packages/core/src/pipeline/HttpContext.ts:703

Register a callback to fire after the Response is sent to the client. Calls container.acquire() synchronously at registration time — before any await — so the request's finally block cannot flush the scope before the callback has a chance to run. This ordering fixes a scope-flush race.

Parameters

callback

() => Promise<void>

Returns

this

Example

ctx.afterResponse(async () => {
  await Analytics.track('page_view', { path: ctx.path() });
});

onResponseReady()

onResponseReady(callback): this

Defined in: packages/core/src/pipeline/HttpContext.ts:744

Register a callback that runs once the final Response exists, before it is returned to the client — the last point at which a header can still be set.

This is what a middleware needs when its work has to land on every response, including one produced by the exception handler. A middleware's own finally block cannot do that: when a handler throws, the pipeline unwinds before any response has been built, so there is nothing to write to. Sessions are the motivating case — a Set-Cookie that only appears on the success path silently drops flashed validation errors on the redirect that carries them.

Finalizers run in registration order and are awaited. An error thrown by one is logged and swallowed, because a failed finalizer must not turn a rendered response into a crash.

Parameters

callback

(response) => Promise<void>

Returns

this

Example

ctx.onResponseReady(async (response) => {
  response.headers.set('X-Request-Id', ctx.requestId);
});

fake()

static fake(url?, init?, container?): HttpContext

Defined in: packages/core/src/pipeline/HttpContext.ts:801

Create a fake HttpContext for unit tests. Does not require a running server.

Parameters

url?

string = "http://localhost/"

init?

RequestInit = {}

container?

ScopedResolver

Returns

HttpContext

Example

const ctx = HttpContext.fake('http://localhost/posts?page=2');
expect(ctx.integer('page')).toBe(2);

tryGet()

static tryGet(): HttpContext<Record<string, string>> | undefined

Defined in: packages/core/src/pipeline/HttpContext.ts:821

The current request's HttpContext, or undefined outside a request. Safe in code that runs both in and out of requests (CLI commands, queue workers, scheduled jobs).

Returns

HttpContext<Record<string, string>> | undefined

Other

user?

optional user?: AuthUser

Defined in: packages/auth/src/augment.ts:18

The authenticated user for this request, populated by AuthMiddleware.


authorize()

authorize<M>(PolicyClass, ability, model?): Promise<void>

Defined in: packages/auth/src/augment.ts:27

Assert the current user is authorized. Throws a 403 ForbiddenError if the policy method returns false.

Type Parameters

M

M

Parameters

PolicyClass

() => Policy<M>

ability

string

model?

M

Returns

Promise<void>

Example

await ctx.authorize(PostPolicy, 'update', post);

requestId

readonly requestId: string

Defined in: packages/core/src/pipeline/HttpContext.ts:67


startedAt

readonly startedAt: number

Defined in: packages/core/src/pipeline/HttpContext.ts:68


url

readonly url: URL

Defined in: packages/core/src/pipeline/HttpContext.ts:69


params

params: TParams

Defined in: packages/core/src/pipeline/HttpContext.ts:74


sessionId?

optional sessionId?: string

Defined in: packages/core/src/pipeline/HttpContext.ts:76


session?

optional session?: SessionContract

Defined in: packages/core/src/pipeline/HttpContext.ts:82


_routeDef?

optional _routeDef?: object

Defined in: packages/core/src/pipeline/HttpContext.ts:85

pattern

pattern: string

controller

controller: string

action

action: string


_transaction?

optional _transaction?: TransactionContext

Defined in: packages/core/src/pipeline/HttpContext.ts:90


locale

locale: string = "en"

Defined in: packages/core/src/pipeline/HttpContext.ts:93


response

response: Response | undefined = undefined

Defined in: packages/core/src/pipeline/HttpContext.ts:96

Set by controllers/route handlers. Read by Application after pipeline runs.


_afterResponseCallbacks

_afterResponseCallbacks: () => Promise<void>[] = []

Defined in: packages/core/src/pipeline/HttpContext.ts:99

Returns

Promise<void>


_responseFinalizers

_responseFinalizers: (response) => Promise<void>[] = []

Defined in: packages/core/src/pipeline/HttpContext.ts:104

Parameters

response

Response

Returns

Promise<void>


_server

_server: RequestIPProvider | undefined = undefined

Defined in: packages/core/src/pipeline/HttpContext.ts:109


_models

readonly _models: Map<string, unknown>

Defined in: packages/core/src/pipeline/HttpContext.ts:113


request

readonly request: Request

Defined in: packages/core/src/pipeline/HttpContext.ts:130


container

readonly container: ScopedResolver

Defined in: packages/core/src/pipeline/HttpContext.ts:131

Redirects

redirect()

redirect(url, status?): void

Defined in: packages/core/src/pipeline/HttpContext.ts:283

Set an HTTP redirect response. Default 302 (Found). Use 303 (See Other) after POST/PUT/DELETE — Inertia and browsers always issue a GET on a 303, preventing form re-submission.

Parameters

url

string

status?

301 | 302 | 303 | 307 | 308

Returns

void

Example

ctx.redirect('/dashboard');       // 302
ctx.redirect('/dashboard', 303);  // 303 after POST

back()

back(status?): void

Defined in: packages/core/src/pipeline/HttpContext.ts:301

Redirect back to the previous page using the Referer header. Falls back to '/' when no Referer is present or when the Referer points to a different origin (prevents open-redirect attacks).

Parameters

status?

301 | 302 | 303 | 307 | 308

Returns

void

Example

ctx.back();       // 302 to Referer
ctx.back(303);    // 303 to Referer (use after Inertia POST)

Request data

path()

path(): string

Defined in: packages/core/src/pipeline/HttpContext.ts:345

The current request pathname (no query string).

Returns

string


fullUrl()

fullUrl(): string

Defined in: packages/core/src/pipeline/HttpContext.ts:354

The full request URL including query string.

Returns

string


host()

host(): string

Defined in: packages/core/src/pipeline/HttpContext.ts:363

The host portion of the URL (hostname + port if non-standard).

Returns

string


subdomains

Get Signature

get subdomains(): Record<string, string>

Defined in: packages/core/src/pipeline/HttpContext.ts:377

Subdomain params captured from a Router.group({ domain }) match.

Example
// Router.group({ domain: ':tenant.app.com' }, () => { ... });
ctx.subdomains;            // { tenant: 'acme' } for acme.app.com
ctx.subdomain('tenant');   // 'acme'
Returns

Record<string, string>


subdomain()

subdomain(name): string | null

Defined in: packages/core/src/pipeline/HttpContext.ts:386

A single subdomain param, or null when absent.

Parameters

name

string

Returns

string | null


is()

is(pattern): boolean

Defined in: packages/core/src/pipeline/HttpContext.ts:401

Test the request path against a glob-style pattern. * matches any sequence of characters except /. ** matches any sequence including /.

Parameters

pattern

string

Returns

boolean

Example

ctx.is('/admin/*')     // true for /admin/users, false for /posts
ctx.is('/posts/**')    // true for /posts/1/comments

ip()

ip(): string | null

Defined in: packages/core/src/pipeline/HttpContext.ts:427

The raw client IP address taken directly from the TCP socket.

Available when running inside Bun.serve() — returns null in tests or any context where the Bun server reference was not injected.

When Bun sits behind a reverse proxy (nginx, Caddy, etc.) this returns the proxy's IP, not the end-user's. Use ThrottleMiddleware's trustedProxies option together with X-Forwarded-For to resolve the real client IP in those deployments.

Returns

string | null


model()

model<T>(name): T

Defined in: packages/core/src/pipeline/HttpContext.ts:451

Retrieve a route-model-bound instance by its parameter name.

The instance is resolved automatically by the framework before the controller runs, using the model bound to the param — implicitly by name, or with .bind() on the route. Throws if no binding was resolved for the given param name (which means either the route has no such param or no binding was registered).

Type Parameters

T

T = unknown

Parameters

name

string

Returns

T

Example

// Route: Router.get('/users/:user', UserController, 'show')

async show(ctx: HttpContext) {
  const user = ctx.model<User>('user');
  return ctx.json({ user });
}

Throws

when no binding was resolved for name (the route has no such param, or nothing bound it).


header(key, fallback?): string | null

Defined in: packages/core/src/pipeline/HttpContext.ts:469

Retrieve a request header by name (case-insensitive). Returns fallback (default null) when the header is absent.

Parameters

key

string

fallback?

string | null

Returns

string | null


bearerToken()

bearerToken(): string | null

Defined in: packages/core/src/pipeline/HttpContext.ts:479

Extract the Bearer token from the Authorization header. Returns null when absent or the header does not use the Bearer scheme.

Returns

string | null


isJson()

isJson(): boolean

Defined in: packages/core/src/pipeline/HttpContext.ts:491

True when the request sends a JSON body (Content-Type: application/json).

Returns

boolean


wantsJson()

wantsJson(): boolean

Defined in: packages/core/src/pipeline/HttpContext.ts:501

True when the client expects a JSON response (Accept: application/json). Useful in exception handlers to decide between an error page and a JSON error.

Returns

boolean


query()

query(key, fallback?): string | undefined

Defined in: packages/core/src/pipeline/HttpContext.ts:517

Read a URL query-string parameter by name. Returns fallback (default undefined) when the param is absent.

Parameters

key

string

fallback?

string

Returns

string | undefined

Example

const page = ctx.query('page', '1');
const q    = ctx.query('search');

integer()

integer(key, fallback?): number | undefined

Defined in: packages/core/src/pipeline/HttpContext.ts:532

Parse a query param or route param as an integer. Checks route params first, then the query string. Returns fallback when the value is absent or not a valid integer.

Parameters

key

string

fallback?

number

Returns

number | undefined

Example

const id   = ctx.integer('id');           // route param
const page = ctx.integer('page', 1);      // query string with default

string()

string(key, fallback?): string | undefined

Defined in: packages/core/src/pipeline/HttpContext.ts:549

Read a query param or route param as a string. Checks route params first, then the query string.

Parameters

key

string

fallback?

string

Returns

string | undefined

Example

const slug = ctx.string('slug');
const sort = ctx.string('sort', 'asc');

boolean()

boolean(key, fallback?): boolean

Defined in: packages/core/src/pipeline/HttpContext.ts:562

Read a query param or route param coerced to a boolean. Truthy values: '1', 'true', 'yes', 'on' (case-insensitive).

Parameters

key

string

fallback?

boolean = false

Returns

boolean

Example

const active = ctx.boolean('active', false);

body()

body<T>(): Promise<T>

Defined in: packages/core/src/pipeline/HttpContext.ts:578

Parse and cache the JSON request body. Subsequent calls return the cached result — safe to call multiple times. Returns {} when the body is absent or not valid JSON.

Type Parameters

T

T extends Record<string, unknown> = Record<string, unknown>

Returns

Promise<T>

Example

const { title, body } = await ctx.body<{ title: string; body: string }>();

input()

input<T>(key, fallback?): T

Defined in: packages/core/src/pipeline/HttpContext.ts:680

Read a value from the merged input bag in priority order: route params → cached JSON body → query string.

Body data is only available here if ctx.body() was awaited earlier in the lifecycle (e.g. by a FormRequest or validate() call). For guaranteed body access, use await ctx.body() or a FormRequest.

Type Parameters

T

T = unknown

Parameters

key

string

fallback?

T

Returns

T

Example

ctx.input('id')          // route param :id or query ?id=
ctx.input('q', 'all')    // with fallback

Responses

json()

json(data, status?): void

Defined in: packages/core/src/pipeline/HttpContext.ts:168

Set a JSON response.

Parameters

data

unknown

status?

number = 200

Returns

void

Example

ctx.json({ user });         // 200
ctx.json({ errors }, 422);  // 422

view()

Call Signature

view(markup, status?): void

Defined in: packages/core/src/pipeline/HttpContext.ts:196

Respond with a server-side view rendered to a full HTML document. Prepends <!DOCTYPE html> and sets Content-Type: text/html.

Accepts either pre-rendered markup, or a view component plus its props. A view component receives the request HttpContext (route params and model bindings live on ctx.params) and the props you pass as a second argument. Pair with core's JSX runtime (add /** @jsxImportSource @zerotal/core */ to view files) so JSX evaluates directly to HTML.

Parameters
markup

ViewMarkup

status?

number

Returns

void

Example
// resources/views/Welcome.tsx
export default function Welcome(ctx: HttpContext, { title }: { title: string }) {
  return <html><body><h1>{title}</h1><p>{ctx.url.pathname}</p></body></html>;
}

// In a route/controller:
ctx.view(Welcome, { title: 'Hello' });

// Or pass already-rendered markup:
ctx.view(Welcome(ctx, { title: 'Hello' }));

Call Signature

view<P>(component, props?, status?): void | Promise<void>

Defined in: packages/core/src/pipeline/HttpContext.ts:197

Respond with a server-side view rendered to a full HTML document. Prepends <!DOCTYPE html> and sets Content-Type: text/html.

Accepts either pre-rendered markup, or a view component plus its props. A view component receives the request HttpContext (route params and model bindings live on ctx.params) and the props you pass as a second argument. Pair with core's JSX runtime (add /** @jsxImportSource @zerotal/core */ to view files) so JSX evaluates directly to HTML.

Type Parameters
P

P extends Record<string, unknown> = Record<string, never>

Parameters
component

(ctx, props) => ViewMarkup | Promise<ViewMarkup>

props?

P

status?

number

Returns

void | Promise<void>

Example
// resources/views/Welcome.tsx
export default function Welcome(ctx: HttpContext, { title }: { title: string }) {
  return <html><body><h1>{title}</h1><p>{ctx.url.pathname}</p></body></html>;
}

// In a route/controller:
ctx.view(Welcome, { title: 'Hello' });

// Or pass already-rendered markup:
ctx.view(Welcome(ctx, { title: 'Hello' }));

markdown()

markdown(content, options?, status?): void

Defined in: packages/core/src/pipeline/HttpContext.ts:244

Render a Markdown string to a full HTML document using Bun's built-in Bun.markdown.html(). Automatically enables tables, strikethrough, tasklists, autolinks, and heading IDs — pass options to override.

Useful for serving .md files as documentation pages:

Parameters

content

string

options?

BunMarkdownOptions & object

status?

number = 200

Returns

void

Example

const content = await Bun.file('./docs/getting-started.md').text();
ctx.markdown(content);

// Custom title / options:
ctx.markdown(content, { title: 'Getting Started', headings: { ids: true } });

html()

html(markup, status?): void

Defined in: packages/core/src/pipeline/HttpContext.ts:265

Respond with a raw HTML string. Unlike view(), no DOCTYPE is prepended — useful for HTML fragments, partials, or when you manage the document shell yourself (e.g. when returning a partial for htmx or Turbo Streams).

Parameters

markup

string | { toString: string; }

status?

number = 200

Returns

void

Example

ctx.html('<p>Updated!</p>');
ctx.html(renderPartial(data), 200);

Session & state

flash()

flash(key, value): void

Defined in: packages/core/src/pipeline/HttpContext.ts:320

Write a value into the session for the next request. Requires SessionMiddleware to be active; silently no-ops if absent.

Use flash() to pass data across a redirect (errors, status messages, etc.). Read it back with flashed() on the next request.

Parameters

key

string

value

unknown

Returns

void

Example

ctx.flash('success', 'Post saved!');
ctx.flash('errors', { email: 'Already taken' });

flashed()

flashed<T>(key): T | undefined

Defined in: packages/core/src/pipeline/HttpContext.ts:334

Read a value that was flashed in the previous request. Returns undefined if the key was not flashed or session is absent.

Type Parameters

T

T = unknown

Parameters

key

string

Returns

T | undefined

Example

const errors  = ctx.flashed<Record<string, string>>('errors');
const success = ctx.flashed<string>('success');