Advanced Middleware Patterns
1. Creating Factory Functions
Example: Configurable middleware factory
export function requirePlan(...plans) {
return (req, res, next) => {
if (!plans.includes(req.user?.plan)) return next(new HttpError(402));
next();
};
}
app.get("/pro", requireAuth, requirePlan("pro","enterprise"), proHandler);
2. Implementing Conditional Middleware
Example: ifEnv helper
const onlyIn = (env, mw) => (req, res, next) => process.env.NODE_ENV === env ? mw(req, res, next) : next();
app.use(onlyIn("development", morgan("dev")));
3. Using Middleware Composition
Example: compose
function compose(...mws) {
return (req, res, next) => {
let i = 0;
const run = (err) => {
if (err) return next(err);
const mw = mws[i++];
if (!mw) return next();
mw(req, res, run);
};
run();
};
}
app.use(compose(requireAuth, requireRole("admin"), loadOrg()));
4. Creating Configurable Middleware
Example: Options + defaults
export function timeout(opts = {}) {
const { ms = 30_000, message = "Request timed out" } = opts;
return (req, res, next) => {
const t = setTimeout(() => {
if (!res.headersSent) res.status(503).json({ error: message });
}, ms);
res.on("finish", () => clearTimeout(t));
res.on("close", () => clearTimeout(t));
next();
};
}
5. Implementing Error Recovery Middleware
Example: Retry on transient error
function retry(fn, { tries = 3 } = {}) {
return async (req, res, next) => {
for (let i = 0; i < tries; i++) {
try { return await fn(req, res, next); }
catch (err) {
if (i === tries - 1 || !err.retryable) return next(err);
}
}
};
}
6. Using Middleware for Request Transformation
Example: Trim string fields
function trimStrings(obj) {
if (!obj || typeof obj !== "object") return obj;
for (const k of Object.keys(obj)) {
if (typeof obj[k] === "string") obj[k] = obj[k].trim();
else if (typeof obj[k] === "object") trimStrings(obj[k]);
}
}
app.use((req, res, next) => { trimStrings(req.body); next(); });
7. Implementing Response Time Middleware
Example: response-time
import responseTime from "response-time";
app.use(responseTime((req, res, time) => {
res.set("X-Response-Time", time.toFixed(1) + "ms");
metrics.histogram("http_request_ms").observe(time);
}));
8. Creating Request ID Middleware
Example: Request ID
import { randomUUID } from "node:crypto";
app.use((req, res, next) => {
req.id = req.get("X-Request-Id") || randomUUID();
res.set("X-Request-Id", req.id);
next();
});
9. Implementing Throttling Middleware
Example: Per-user concurrency limit
const inflight = new Map();
export function maxConcurrent(n) {
return (req, res, next) => {
const key = req.user?.sub || req.ip;
const count = inflight.get(key) || 0;
if (count >= n) return next(new HttpError(429, "Too many concurrent requests"));
inflight.set(key, count + 1);
res.on("finish", () => inflight.set(key, (inflight.get(key) || 1) - 1));
next();
};
}
10. Using Middleware for Feature Flags
Example: Flag-gated route
export const requireFlag = (flag) => async (req, res, next) => {
const enabled = await flags.isEnabled(flag, { userId: req.user?.sub });
enabled ? next() : next(new HttpError(404)); // hide route entirely
};
app.get("/beta/feature", requireAuth, requireFlag("beta_feature"), betaHandler);