typescriptintermediate
Middleware Chain Pattern
Implement the middleware/pipeline pattern for composable request processing without Express.
typescriptPress ⌘/Ctrl + Shift + C to copy
type Context = {
request: { method: string; path: string; headers: Record<string, string>; body?: unknown };
response: { status: number; body: unknown; headers: Record<string, string> };
state: Record<string, unknown>;
};
type Next = () => Promise<void>;
type Middleware = (ctx: Context, next: Next) => Promise<void>;
class Pipeline {
private middlewares: Middleware[] = [];
use(mw: Middleware): this {
this.middlewares.push(mw);
return this;
}
async execute(ctx: Context): Promise<Context> {
let index = -1;
const dispatch = async (i: number): Promise<void> => {
if (i <= index) throw new Error('next() called multiple times');
index = i;
const mw = this.middlewares[i];
if (mw) await mw(ctx, () => dispatch(i + 1));
};
await dispatch(0);
return ctx;
}
}
// Logger middleware
const logger: Middleware = async (ctx, next) => {
const start = Date.now();
console.log(`→ ${ctx.request.method} ${ctx.request.path}`);
await next();
console.log(`← ${ctx.response.status} (${Date.now() - start}ms)`);
};
// Auth middleware
const auth: Middleware = async (ctx, next) => {
const token = ctx.request.headers['authorization'];
if (!token) {
ctx.response = { status: 401, body: { error: 'Unauthorized' }, headers: {} };
return; // Don't call next
}
ctx.state.userId = 'user-123';
await next();
};
// Handler
const handler: Middleware = async (ctx, next) => {
ctx.response = {
status: 200,
body: { message: 'Hello', userId: ctx.state.userId },
headers: { 'content-type': 'application/json' },
};
await next();
};
// Usage
async function main() {
const app = new Pipeline().use(logger).use(auth).use(handler);
const ctx: Context = {
request: { method: 'GET', path: '/api/me', headers: { authorization: 'Bearer token' } },
response: { status: 200, body: null, headers: {} },
state: {},
};
const result = await app.execute(ctx);
console.log('Response:', result.response);
}
main();Use Cases
- Custom HTTP framework
- Request processing pipelines
- Plugin architecture
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
typescriptintermediate
Middleware Pattern and Composition
Implement the middleware pattern for composable request processing with next() and error handling.
Best for: Request processing pipelines
#nodejs#middleware
typescriptintermediate
TypeScript Typed Event Emitter
Create type-safe event emitters in Node.js with full TypeScript support and autocomplete.
Best for: Type-safe pub/sub communication between modules
#nodejs#events
typescriptintermediate
Event-Driven Architecture Pattern
Build loosely coupled systems with typed event bus, async event handlers, and domain event patterns.
Best for: Microservice communication
#nodejs#events
typescriptadvanced
JavaScript Proxy Handler Pattern
Use Proxy and Reflect to create observable objects, validation layers, and dynamic API clients.
Best for: Observable state management
#nodejs#proxy