Claude-initial-setup middleware-patterns
install
source · Clone the upstream repo
git clone https://github.com/VersoXBT/claude-initial-setup
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/VersoXBT/claude-initial-setup "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/express-node/middleware-patterns" ~/.claude/skills/versoxbt-claude-initial-setup-middleware-patterns && rm -rf "$T"
manifest:
skills/express-node/middleware-patterns/SKILL.mdsource content
Express Middleware Patterns
Patterns for building robust Express.js middleware chains.
When to Use
- User is setting up an Express.js application middleware stack
- User needs authentication or authorization middleware
- User asks about rate limiting, CORS, or request validation
- User is debugging middleware execution order
- User needs to write custom middleware
Core Patterns
Middleware Execution Order
Middleware executes in the order it is registered. Order matters: authentication must run before authorization, and error handlers must be last.
import express from 'express' const app = express() // 1. Built-in middleware app.use(express.json({ limit: '10kb' })) app.use(express.urlencoded({ extended: true })) // 2. Security / CORS app.use(corsMiddleware) // 3. Rate limiting app.use(rateLimiter) // 4. Request logging app.use(requestLogger) // 5. Routes (with route-specific middleware) app.use('/api/v1/auth', authRoutes) app.use('/api/v1/users', authenticate, userRoutes) app.use('/api/v1/admin', authenticate, authorize('admin'), adminRoutes) // 6. 404 handler app.use(notFoundHandler) // 7. Error handler (must be last, must have 4 parameters) app.use(errorHandler)
Authentication Middleware
Verify tokens and attach user context to the request object.
import { Request, Response, NextFunction } from 'express' import jwt from 'jsonwebtoken' interface AuthRequest extends Request { user?: { id: string; role: string } } function authenticate(req: AuthRequest, res: Response, next: NextFunction): void { const header = req.headers.authorization if (!header?.startsWith('Bearer ')) { res.status(401).json({ error: 'Missing authorization header' }) return } const token = header.slice(7) try { const payload = jwt.verify(token, process.env.JWT_SECRET!) as { id: string; role: string } req.user = { id: payload.id, role: payload.role } next() } catch { res.status(401).json({ error: 'Invalid or expired token' }) } } function authorize(...roles: string[]) { return (req: AuthRequest, res: Response, next: NextFunction): void => { if (!req.user || !roles.includes(req.user.role)) { res.status(403).json({ error: 'Insufficient permissions' }) return } next() } }
Rate Limiting
Protect endpoints from abuse. Use different limits for different routes.
import rateLimit from 'express-rate-limit' const globalLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, standardHeaders: true, legacyHeaders: false, message: { error: 'Too many requests, try again later' }, }) const authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 5, // Strict limit for auth endpoints message: { error: 'Too many login attempts' }, }) app.use(globalLimiter) app.use('/api/v1/auth/login', authLimiter)
CORS Configuration
Configure Cross-Origin Resource Sharing for frontend clients.
import cors from 'cors' const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || [] const corsMiddleware = cors({ origin: (origin, callback) => { if (!origin || allowedOrigins.includes(origin)) { callback(null, true) } else { callback(new Error('Not allowed by CORS')) } }, methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], allowedHeaders: ['Content-Type', 'Authorization'], credentials: true, maxAge: 86400, })
Request Validation Middleware
Validate request body, query, and params using Zod. Create a reusable factory.
import { z, ZodSchema } from 'zod' import { Request, Response, NextFunction } from 'express' function validate(schema: { body?: ZodSchema query?: ZodSchema params?: ZodSchema }) { return (req: Request, res: Response, next: NextFunction): void => { const errors: Record<string, unknown> = {} if (schema.body) { const result = schema.body.safeParse(req.body) if (!result.success) errors.body = result.error.flatten() } if (schema.query) { const result = schema.query.safeParse(req.query) if (!result.success) errors.query = result.error.flatten() } if (schema.params) { const result = schema.params.safeParse(req.params) if (!result.success) errors.params = result.error.flatten() } if (Object.keys(errors).length > 0) { res.status(400).json({ error: 'Validation failed', details: errors }) return } next() } } // Usage const CreateUserSchema = z.object({ name: z.string().min(1).max(100), email: z.string().email(), }) router.post('/users', validate({ body: CreateUserSchema }), createUser)
Anti-Patterns
- Forgetting to call
-- Every middleware must callnext()
or send a response. Forgetting causes the request to hang indefinitely.next() - Error handler with 3 parameters -- Express only recognizes error middleware if it has exactly 4 parameters:
. Three parameters means it is treated as regular middleware.(err, req, res, next) - Registering error handlers before routes -- Error handlers must come after all routes and other middleware. Express routes to the first matching handler.
- Blocking the event loop in middleware -- Synchronous CPU-heavy operations (bcrypt with high rounds, large JSON parsing) block all requests. Use async alternatives or worker threads.
- Applying auth middleware globally when some routes are public -- Apply auth selectively to protected route groups, not to the entire app.
Quick Reference
Middleware signature: (req, res, next) => void Error middleware: (err, req, res, next) => void Order: parsing -> security -> rate-limit -> logging -> routes -> 404 -> errors Route-specific: router.get('/path', middleware1, middleware2, handler) Router-level: router.use(middleware) App-level: app.use(middleware)