Middleware: logging and error handling
Middleware is a function that sits between the request coming in and your route handler. Authentication, logging, request IDs, rate limiting, error handling. Anything that has to apply across many routes belongs as middleware.
import { Request, Response, NextFunction } from 'express';
import winston from 'winston';
export const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json(),
),
transports: [new winston.transports.Console()],
});
export function requestLogger(req: Request, res: Response, next: NextFunction) {
logger.info(req.method + ' ' + req.originalUrl);
next(); // do not forget this
}
export function errorHandler(err: any, req: Request, res: Response, next: NextFunction) {
logger.error(err.message || 'Internal Server Error');
res.status(err.status || 500).json({
error: err.message || 'Something went wrong',
});
}Logger and error handler middleware. The logger uses Winston so logs are structured.
The single most common bug with middleware: forgetting to call next(). Without it, the request hangs forever, the client times out, and you wonder why your server stopped responding. Make next() the muscle memory: every middleware call ends with it unless you have explicitly sent a response.
Express identifies error-handling middleware by counting parameters. Four parameters (err, req, res, next) tells Express this function is for handling errors. Even if you do not use next, it has to be in the signature. It is one of those quirks you only need to learn once.
import express from 'express';
import { bookRouter } from './routes/book.routes';
import { requestLogger, errorHandler } from './middlewares/logger';
export const app = express();
app.use(express.json());
app.use(requestLogger); // runs for every request
app.use('/api/books', bookRouter);
app.use(errorHandler); // catches errors from any handlerWire the middleware into the app. Order matters: logger first, error handler last.
Quiz: Quiz
Loading practiceโฆ
Validation checklist: Build the layered API
Loading practiceโฆ
Your in-memory array works perfectly until you restart the server. Then everything you added is gone. Next up you replace the array with a real Postgres database, and you see the payoff of the layers you just built: only the data and service files change. Routes and controllers do not move at all.
Checkpoint: REST APIs with Express checkpoint
Loading practiceโฆ