iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Middleware

Express middleware are functions that receive (req, res, next). They run in order; each can short-circuit by responding or pass control with next(). Auth, logging, validation, error handling — all middleware.

Built-in + custom + error handling

EXAMPLE
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import morgan from 'morgan';
import rateLimit from 'express-rate-limit';

const app = express();

// 1) Global middleware — order matters!
app.use(helmet());                          // security headers
app.use(cors({ origin: 'https://app.example.com', credentials: true }));
app.use(morgan('combined'));                // request logging
app.use(express.json({ limit: '100kb' }));
app.use(express.urlencoded({ extended: true }));

// 2) Rate limit
app.use('/api', rateLimit({
    windowMs: 60_000,
    max:      100,
    standardHeaders: true,
    legacyHeaders:   false,
}));

// 3) Custom middleware — adding a request ID
app.use((req, _res, next) => {
    req.id = crypto.randomUUID();
    next();
});

// 4) Auth middleware — short-circuit on failure
function requireAuth(req, res, next) {
    const token = req.headers.authorization?.replace('Bearer ', '');
    if (!token) return res.status(401).json({ error: 'no token' });
    try {
        req.user = verifyJWT(token);
        next();
    } catch (e) {
        return res.status(401).json({ error: 'invalid token' });
    }
}

// 5) Apply to specific routes
app.get('/me',    requireAuth, getProfile);
app.use('/admin', requireAuth, requireRole('admin'), adminRouter);

// 6) Validation middleware
import { z } from 'zod';
const validate = (schema) => (req, res, next) => {
    const result = schema.safeParse(req.body);
    if (!result.success) return res.status(400).json({ errors: result.error.issues });
    req.body = result.data;
    next();
};

app.post('/users', validate(NewUser), createUser);

// 7) Async middleware — wrap to forward errors
const asyncHandler = (fn) => (req, res, next) =>
    Promise.resolve(fn(req, res, next)).catch(next);

app.get('/users/:id', asyncHandler(async (req, res) => {
    const user = await db.users.findOne({ id: req.params.id });
    if (!user) throw new HttpError(404, 'not found');
    res.json(user);
}));

// 8) Error-handling middleware — 4 args, must be LAST
app.use((err, req, res, _next) => {
    log.error({ reqId: req.id, err }, 'unhandled');
    res.status(err.status ?? 500).json({ error: err.message ?? 'internal' });
});

// 9) Conditional middleware — apply only when needed
const inDev = process.env.NODE_ENV !== 'production';
if (inDev) app.use(require('morgan')('dev'));

// 10) Router-level middleware
import { Router } from 'express';
const posts = Router();
posts.use(requireAuth);                     // all posts routes need auth
posts.get('/', listPosts);
posts.post('/', validate(NewPost), createPost);
app.use('/posts', posts);

Why it matters

Middleware order IS the request pipeline. Keep security headers + CORS + body parsing at the top; auth before the route; error handler at the bottom. The mental model is “outermost to innermost.”

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
function logger(req, res, next) {
    console.log(req.method, req.url);
    next();
}
app.use(logger);
Try it Yourself »

Discussion

Loading…