Middleware
VentureKit provides a composable middleware system for cross-cutting concerns like logging, CORS, timeouts, and error handling.
How Middleware Works
Section titled “How Middleware Works”Middleware wraps handler execution in a stack pattern. Each middleware can:
- Run code before the handler
- Run code after the handler
- Catch and handle errors
- Short-circuit the request (return a response without calling the handler)
Request → ErrorBoundary → Logging → Custom Middleware → Handler → ResponseBuilt-in Middleware
Section titled “Built-in Middleware”Error Boundary
Section titled “Error Boundary”Catches all errors and formats them into structured JSON responses. This is applied automatically to every handler.
Logging Middleware
Section titled “Logging Middleware”Logs request start, completion, and failures with timing information:
import { loggingMiddleware, createLogger } from '@venturekit/runtime';
const logger = createLogger({ minLevel: 'info' });const logging = loggingMiddleware(logger);CORS Middleware
Section titled “CORS Middleware”Adds CORS headers and handles preflight OPTIONS requests:
import { corsMiddleware } from '@venturekit/runtime';
const cors = corsMiddleware({ allowOrigins: ['https://app.example.com'], allowMethods: ['GET', 'POST', 'PUT', 'DELETE'], allowHeaders: ['Content-Type', 'Authorization'], allowCredentials: true, maxAge: 3600,});Timeout Middleware
Section titled “Timeout Middleware”Enforces a maximum request duration:
import { timeoutMiddleware } from '@venturekit/runtime';
const timeout = timeoutMiddleware(5000); // 5 secondsUsing Middleware in Handlers
Section titled “Using Middleware in Handlers”Pass middleware in the handler config:
import { handler, corsMiddleware, timeoutMiddleware } from '@venturekit/runtime';
export const main = handler(async (_body, ctx, logger) => { return { ok: true };}, { middleware: [ timeoutMiddleware(5000), ],});Rate Limiting
Section titled “Rate Limiting”Built-in rate limiting with distributed DynamoDB storage (production) or in-memory (dev):
import { rateLimitMiddleware, createDefaultRateLimiter } from '@venturekit/runtime';
// Zero-config — 100 req/min per IP, auto-selects DynamoDB or memoryconst rateLimit = rateLimitMiddleware({ check: await createDefaultRateLimiter(),});
// Strict preset for auth endpoints — 20 req/minconst authRateLimit = rateLimitMiddleware({ check: await createDefaultRateLimiter({ preset: 'strict' }),});Presets:
| Preset | Limit | Window | Use Case |
|---|---|---|---|
relaxed | 200/min | 60s | Internal APIs, dev |
standard | 100/min | 60s | Public APIs (default) |
strict | 20/min | 60s | Auth, sensitive ops |
api-key | 1000/min | 60s | Authenticated consumers |
In production, rate limit counters are stored in DynamoDB with atomic increments and TTL cleanup. See the Lambda Invocation guide for more.
Writing Custom Middleware
Section titled “Writing Custom Middleware”A middleware is an object with a name and fn:
import type { Middleware } from '@venturekit/runtime';
const myMiddleware: Middleware = { name: 'myMiddleware', fn: async (ctx, next) => { // Run before handler console.log('Before:', ctx.path);
// Call the next middleware or handler const response = await next();
// Run after handler (optional) return response; },};Composing Middleware
Section titled “Composing Middleware”Use compose() to combine multiple middleware into a single function:
import { compose } from '@venturekit/runtime';
const stack = compose([ loggingMiddleware(logger), corsMiddleware({ /* ... */ }), timeoutMiddleware(5000), rateLimitMiddleware,]);Integration with Tenancy and Auth
Section titled “Integration with Tenancy and Auth”Feature packages provide their own middleware:
import { createTenantMiddleware, createQuotaMiddleware } from '@venturekit-pro/tenancy';
export const main = handler(async (_body, ctx, logger) => { // ctx.tenant is populated by tenant middleware return { tenantId: ctx.tenant?.id };}, { scopes: ['api.read'], middleware: [ createTenantMiddleware({ strategy: 'subdomain' }), createQuotaMiddleware(), ],});