Context API
The CloudwerkContext object provides access to bindings, utilities, and request information throughout your application.
Overview
Section titled “Overview”There are three ways to access context in Cloudwerk:
- Importable helpers (recommended) - Import
params,request,get,setdirectly getContext()- Call to get the full context objectcontextparameter (loaders only) - Receive context as a function parameter
All three methods work anywhere within a request: route handlers, loaders, pages, layouts, and middleware.
// Importable helpers - work everywhere (recommended)import { params, request, get } from '@cloudwerk/core/context'
export async function GET() { const userId = params.id const user = get<User>('user') return json({ userId, user })}
// In a loader - importable helpers or context parameter both workimport { params, get } from '@cloudwerk/core/context'
export async function loader({ context }: LoaderArgs) { // Option 1: Use importable helpers (recommended) const userId = params.id const user = get<User>('user')
// Option 2: Use context parameter const userId2 = context.params.id
return { userId, user };}
// getContext() - also works everywhereimport { getContext, json } from '@cloudwerk/core'
export async function GET() { const ctx = getContext() return json({ userId: ctx.params.id })}
// In middlewareimport { set } from '@cloudwerk/core/context'
export const middleware: Middleware = async (request, next) => { set('user', await validateSession(request)) return next()};Importable Context Helpers
Section titled “Importable Context Helpers”Import context helpers directly from @cloudwerk/core/context. These work in route handlers, loaders, pages, layouts, and middleware - anywhere within a request:
import { params, request, get, set, getRequestId } from '@cloudwerk/core/context'
export async function GET() { const userId = params.id const authHeader = request.headers.get('Authorization') const user = get<User>('user') // From middleware return json({ userId, requestId: getRequestId() })}Available Exports
Section titled “Available Exports”| Export | Type | Description |
|---|---|---|
params | Record<string, string> | Route parameters from dynamic segments |
request | Request | Current request object |
env | Record<string, unknown> | Environment bindings |
executionCtx | ExecutionContext | For waitUntil() background tasks |
getRequestId() | () => string | Get unique request ID for tracing |
get<T>(key) | (key: string) => T | undefined | Get middleware data |
set<T>(key, value) | (key: string, value: T) => void | Set data for downstream handlers |
Examples
Section titled “Examples”Access route parameters:
import { params } from '@cloudwerk/core/context'
// For route /users/[id]/posts/[postId]export async function GET() { const { id, postId } = params return json({ userId: id, postId })}Access request data:
import { request } from '@cloudwerk/core/context'
export async function POST() { const body = await request.json() const contentType = request.headers.get('Content-Type') return json({ received: body })}Background tasks with executionCtx:
import { executionCtx, request } from '@cloudwerk/core/context'import { json } from '@cloudwerk/core'
export async function POST() { const data = await request.json()
// Fire-and-forget background task executionCtx.waitUntil( sendAnalytics({ event: 'data_submitted', data }) )
return json({ success: true })}Share data between middleware and handlers:
// middleware.tsimport { set } from '@cloudwerk/core/context'
export const middleware: Middleware = async (request, next) => { const user = await validateSession(request) set('user', user) return next()}
// route.tsimport { get } from '@cloudwerk/core/context'import { json } from '@cloudwerk/core'
export async function GET() { const user = get<User>('user') if (!user) { return new Response('Unauthorized', { status: 401 }) } return json({ user })}Properties
Section titled “Properties”Access to all Cloudflare bindings:
interface CloudwerkContext { env: { DB: D1Database; // D1 binding KV: KVNamespace; // KV binding R2: R2Bucket; // R2 binding MY_QUEUE: Queue; // Queue binding DURABLE_OBJECT: DurableObjectNamespace; [key: string]: unknown; // Custom bindings };}Query builder for D1 database:
// Selectconst users = await context.db .selectFrom('users') .where('status', '=', 'active') .orderBy('created_at', 'desc') .limit(10) .execute();
// Insertconst user = await context.db .insertInto('users') .returning(['id', 'email']) .executeTakeFirst();
// Updateawait context.db .updateTable('users') .set({ name: 'Jane' }) .where('id', '=', userId) .execute();
// Deleteawait context.db .deleteFrom('users') .where('id', '=', userId) .execute();KV namespace helper:
// Get valueconst value = await context.kv.get('key');const jsonValue = await context.kv.get<User>('key', 'json');
// Set valueawait context.kv.put('key', 'value');await context.kv.put('key', JSON.stringify(data), { expirationTtl: 3600,});
// Deleteawait context.kv.delete('key');R2 bucket helper:
// Get objectconst object = await context.r2.get('path/to/file.txt');if (object) { const text = await object.text();}
// Put objectawait context.r2.put('path/to/file.txt', content, { httpMetadata: { contentType: 'text/plain' },});
// Deleteawait context.r2.delete('path/to/file.txt');queues
Section titled “queues”Queue producers:
// Send message
// Send batchawait context.queues.MY_QUEUE.sendBatch([]);Authentication utilities:
interface AuthContext { // Get current user (null if not authenticated) getUser(): Promise<User | null>;
// Require user (throws RedirectError if not authenticated) requireUser(): Promise<User>;
// Session management createSession(data: SessionData): Promise<void>; destroySession(): Promise<void>; getSession(): Promise<Session | null>;
// OAuth helpers getOAuthUrl(provider: string): string; exchangeOAuthCode(provider: string, code: string): Promise<OAuthTokens>; getOAuthProfile(provider: string, tokens: OAuthTokens): Promise<OAuthProfile>;}Usage:
// Get current userconst user = await context.auth.getUser();if (!user) { throw new RedirectError('/login');}
// Or use requireUserconst user = await context.auth.requireUser(); // Throws if not authenticated
// Create sessionawait context.auth.createSession({ userId: user.id, email: user.email,});
// Destroy session (logout)await context.auth.destroySession();request
Section titled “request”The incoming Request object:
// Access request propertiesconst url = new URL(context.request.url);const method = context.request.method;const headers = context.request.headers;
// Parse bodyconst json = await context.request.json();const formData = await context.request.formData();const text = await context.request.text();waitUntil
Section titled “waitUntil”Extend request lifetime for background tasks:
export async function POST(request: Request, { context }: CloudwerkHandlerContext) { // Respond immediately const response = json({ success: true });
// Continue processing in background context.waitUntil( sendAnalyticsEvent({ type: 'api_call', endpoint: '/api/users' }) );
return response;}Cloudflare-specific request properties:
interface CfProperties { asn: number; // ASN of the incoming request asOrganization: string; // Organization name city: string; // City colo: string; // Cloudflare data center continent: string; // Continent code country: string; // Country code latitude: string; // Latitude longitude: string; // Longitude postalCode: string; // Postal code region: string; // Region/state regionCode: string; // Region code timezone: string; // Timezone tlsVersion: string; // TLS version tlsCipher: string; // TLS cipher}
// Usageconst { country, city, timezone } = context.cf;console.log(`Request from ${city}, ${country} (${timezone})`);Response Helpers
Section titled “Response Helpers”json()
Section titled “json()”Create JSON response:
export async function GET(request: Request, { context }: CloudwerkHandlerContext) { return context.json({ message: 'Hello' }); return context.json({ error: 'Not found' }, { status: 404 }); return context.json(data, { status: 201, headers: { 'X-Custom': 'value' }, });}redirect()
Section titled “redirect()”Create redirect response:
return context.redirect('/dashboard');return context.redirect('/login', 302); // Temporary redirectreturn context.redirect('https://example.com', 301); // Permanent redirecthtml()
Section titled “html()”Create HTML response:
return context.html('<h1>Hello, World!</h1>');return context.html(htmlContent, { status: 200 });text()
Section titled “text()”Create text response:
return context.text('Hello, World!');return context.text('Not found', { status: 404 });stream()
Section titled “stream()”Create streaming response:
const stream = new ReadableStream({ start(controller) { controller.enqueue('Hello, '); controller.enqueue('World!'); controller.close(); },});
return context.stream(stream, { headers: { 'Content-Type': 'text/plain' },});Type Definitions
Section titled “Type Definitions”interface CloudwerkContext { env: Env; db: DatabaseClient; kv: KVHelper; r2: R2Helper; queues: Record<string, Queue>; auth: AuthContext; request: Request; waitUntil: (promise: Promise<unknown>) => void; cf: CfProperties;
// Response helpers json<T>(data: T, init?: ResponseInit): Response; redirect(url: string, status?: number): Response; html(content: string, init?: ResponseInit): Response; text(content: string, init?: ResponseInit): Response; stream(stream: ReadableStream, init?: ResponseInit): Response;}
interface CloudwerkHandlerContext { params: Record<string, string>; context: CloudwerkContext;}
interface LoaderArgs { request: Request; params: Record<string, string>; context: CloudwerkContext;}Next Steps
Section titled “Next Steps”- Bindings Reference - All Cloudflare bindings
- Authentication Guide - Auth patterns
- Database Guide - D1 database usage