Beware of Middleware: Why Overusing Middleware Can Be Harmful
The article argues that while middleware can simplify handling cross‑cutting concerns in HTTP APIs, overusing it leads to tangled, untestable code, and proposes refactoring middleware logic into pure functions with explicit inputs and outputs to improve clarity and maintainability.
When building an HTTP API, developers often distinguish between route‑specific behavior (controllers and models) and behavior that applies to many routes, which is usually implemented as middleware. The author compares controllers to a lexer/parser that transforms unconstrained request data into a more constrained model representation.
Middleware, however, operates on the raw request and response objects, mutating them or causing side effects without returning meaningful values. Simple middleware examples such as rate limiting, authorization checks, and logging are presented, followed by Express code illustrating how they are typically chained.
const rateLimitingMiddleware = async (req, res) => {
const ip = req.headers['ip'];
db.incrementNRequests(ip);
if (await db.nRequestsSince(Date.now() - 60000, ip) > 100) {
return res.send(423);
}
};
const authorizationMiddleware = async (req, res) => {
const account = await db.accountByAuthorization(req.headers['authorization']);
if (!account) { return res.send(401); }
};
const loggingMiddleware = async (req, res) => {
if (Math.random() <= .1) {
console.log(`request received ${req.method} ${req.path}
${req.body}`);
}
};
app.use([rateLimitingMiddleware, authorizationMiddleware, loggingMiddleware].map(f => (req, res, next) =>
f(req, res).then(() => next()).catch(err => next(err))
));The author then suggests a different approach: write each operation as a pure function that receives explicit parameters and returns a result, then expose a thin middleware that translates the HTTP request into calls to those functions. This yields a "slim controller" that is easier to reason about.
const shouldRateLimit = async (ip) => {
return await db.nRequestsSince(Date.now() - 60000, ip) < 100;
};
const isAuthorizationValid = async (authorization) => {
return !!await db.accountByAuthorization(authorization);
};
const emitLog = (method, path, body) => {
if (Math.random() < .1) {
console.log(`request received ${method} ${path}
${body}`);
}
};
const mw = async (req, res) => {
const { ip, authorization } = req.headers;
const { method, path, body } = req;
if (await shouldRateLimit(ip)) { return res.send(423); }
if (!await isAuthorizationValid(authorization)) { return res.send(401); }
emitLog(method, path, body);
};
app.use((req, res, next) => {
mw(req, res).then(() => next()).catch(err => next(err));
});When additional requirements such as admin‑only logging and exempting admins from rate limits are introduced, the author shows how naive middleware ordering can cause bugs, and demonstrates a refactor that moves admin checks into the pure functions, reducing database calls and eliminating hidden dependencies.
const authorizationMiddleware = async (req, res) => {
const account = await db.accountByAuthorization(req.headers['authorization']);
if (!account) { return res.send(401); }
req.isAdmin = account.isAdmin();
};
const rateLimitingMiddleware = async (req, res) => {
if (req.isAdmin) return;
const ip = req.headers['ip'];
db.incrementNRequests(ip);
if (await db.nRequestsSince(Date.now() - 60000, ip) > 100) { return res.send(423); }
};
const loggingMiddleware = async (req, res) => {
if (req.isAdmin || Math.random() <= .1) {
console.log(`request received ${req.method} ${req.path}
${req.body}`);
}
};Finally, the article reflects on the broader lesson: avoid letting frameworks dictate design; instead, write pure functions, pass required data explicitly, and return results, much like building a compiler. This mindset helps prevent the misuse of middleware and keeps codebases maintainable.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
