Documentation
Context (ctx)
Every handler and middleware receives a single ctx object that bundles the incoming request, route metadata, and all response helpers. It is the sole argument to every handler — no juggling req and res separately.
Request access#
The raw Request object is on ctx.req. A pre-parsed URL instance is on ctx.url. Both are read-only.
app.get('/info', (ctx) => { const method = ctx.req.method // 'GET' const pathname = ctx.url.pathname // '/info' const host = ctx.url.host // 'api.example.com' const ua = ctx.req.headers.get('user-agent') return ctx.json({ method, pathname, host, ua })})Route params#
Named segments and wildcard captures are on ctx.params — a Record<string, string> that is always URL-decoded.
app.get('/users/:id', (ctx) => { const id = ctx.params.id // '42' return ctx.json({ id })}) app.get('/files/*', (ctx) => { const path = ctx.params['*'] // 'assets/logo.png' return ctx.text(path)})See Params for the full reference.
Query strings#
ctx.query(name) returns a single query value or null. ctx.query() returns all params as a record.
// GET /search?q=edge&limit=20app.get('/search', (ctx) => { const q = ctx.query('q') // 'edge' const limit = ctx.query('limit') // '20' const all = ctx.query() // { q: 'edge', limit: '20' } return ctx.json({ q, limit, all })})Request headers#
ctx.header(name) returns the value of a single request header as a string or null (case-insensitive).
app.get('/whoami', (ctx) => { const auth = ctx.header('authorization') const accept = ctx.header('accept') const tenant = ctx.header('x-tenant-id') return ctx.json({ auth, accept, tenant })})Environment bindings#
Runtime environment bindings (Cloudflare Workers env, process.env, etc.) are available on ctx.env. Cast it to your declared Env interface for type safety.
interface Env { DB: D1Database API_SECRET: string} app.get('/secret', (ctx) => { const env = ctx.env as Env return ctx.text(env.API_SECRET)})State#
ctx.state is a Map that lives for the lifetime of a single request. Use it to pass data between middleware and handlers without mutating global scope.
// Middleware: attach user after authapp.use(async (ctx, next) => { const token = ctx.header('authorization') if (token) { ctx.state.set('user', { id: '42', name: 'Alice' }) } return next()}) // Handler: read from stateapp.get('/me', (ctx) => { const user = ctx.state.get('user') return ctx.json(user ?? null)})Tip
ctx.decorate /ctx.get) for values that plugins and middleware expose as part of a stable API. Use ctx.state for ad-hoc within-request data passing.Decorations#
Plugins and middleware can attach named values to ctx with ctx.decorate(key, value). Read them back with ctx.get(key). Check existence with ctx.has(key).
import { definePlugin } from '@kynetra/fx' export const dbPlugin = definePlugin({ name: 'db', register(app) { app.decorateContext('db', (ctx) => { // factory called per-request — binds D1 from env return (ctx.env as any).DB }) },}) // In handlers:app.get('/users', (ctx) => { const db = ctx.get('db') // D1Database return ctx.json({ ok: true })})Contract data#
When using app.route() with input or query schemas, the validated and typed values appear on ctx.input and ctx.validatedQuery respectively.
app.route({ method: 'POST', path: '/items', input: fx.object({ name: fx.string(), qty: fx.number() }), handler(ctx) { // ctx.input: { name: string; qty: number } const { name, qty } = ctx.input return ctx.json({ name, qty }, { status: 201 }) },})See Contracts for details.
Full ctx reference#
| Name | Type | Description |
|---|---|---|
| req | Request | The incoming Web Standards Request object. |
| url | URL | Pre-parsed URL instance for the request. |
| params | Record<string, string> | URL-decoded route parameters including wildcard capture as params["*"]. |
| query(name?) | string | null | Record<string, string> | Query-string accessor. No arg returns all params as a record. |
| header(name) | string | null | Case-insensitive request header accessor. |
| env | unknown | Runtime environment / bindings object. Cast to your Env type. |
| state | Map<string, unknown> | Per-request key-value store for passing data between middleware. |
| input | T (inferred) | Validated and typed request body (set by app.route() with input schema). |
| validatedQuery | T (inferred) | Validated and typed query params (set by app.route() with query schema). |
| decorate(key, value) | void | Attach a named value to this ctx instance. |
| get<T>(key) | T | Read a decoration or context-decorator value by key. |
| has(key) | boolean | Check whether a decoration exists on this ctx instance. |
| json(data, init?) | Response | Return a JSON response. |
| text(s, init?) | Response | Return a plain-text response. |
| html(s, init?) | Response | Return an HTML response. |
| redirect(url, status?) | Response | Return a redirect response (default 302). |
| stream(body, init?) | Response | Return a streaming response. |
| response(body?, init?) | Response | Return a raw Response. |
| status(code) | ctx (chainable) | Set the response status code. Chainable. |
| set(name, value) | void | Set a response header. |
| append(name, value) | void | Append to a response header. |
| cookie(name) | string | null | Read a request cookie by name. |
| setCookie(name, value, opts?) | void | Set a response cookie. |
| jsonBody<T>() | Promise<T> | Parse the request body as JSON. |
| textBody() | Promise<string> | Parse the request body as text. |
| formBody() | Promise<FormData> | Parse the request body as FormData (multipart or URL-encoded). |