Topic 44 of 55
Express Custom Middleware Flow
Overview
Middleware functions are the backbone of Express. They are functions that have access to the request (`req`), response (`res`), and the `next` function. They can execute any code, modify the request/response, end the cycle, or pass control to the next middleware in the stack.
Syntax
javascript
const express = require('express');
const app = express();
// A simple custom middleware function
const requestLogger = (req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} to ${req.url}`);
// CRITICAL: You must call next() to pass control to the next function.
// If you don't, the request will hang forever!
next();
};
// Apply middleware globally (runs on EVERY request)
app.use(requestLogger);
// Apply middleware to a specific route ONLY
const checkAdmin = (req, res, next) => {
if (req.headers['x-admin'] !== 'true') {
// We end the cycle here, next() is NOT called
return res.status(403).send('Forbidden');
}
next();
};
app.get('/admin', checkAdmin, (req, res) => {
res.send('Welcome, Admin!');
});Common Pitfalls
- Forgetting to call `next()` is the #1 cause of hanging Express applications.
- You cannot modify the response body or headers after `res.send()` or `res.json()` has been called, even if you try to do it in a subsequent middleware.
Real-World Example
Modifying the request object to pass data to the final route handler:
example
javascript
const extractUser = async (req, res, next) => {
const token = req.headers.authorization;
if (!token) return next(); // Not logged in, but let them continue
// Fetch user from DB and attach it directly to the req object
const user = await db.getUserByToken(token);
req.user = user;
next();
};
app.use(extractUser);
app.get('/profile', (req, res) => {
if (!req.user) {
return res.status(401).send('Please log in');
}
// We can now access the user data injected by the middleware!
res.json({ name: req.user.name, email: req.user.email });
});