ExpressJS - Middleware
Express.js - Understanding Middleware
Section titled “Express.js - Understanding Middleware”Middleware functions are the heart of Express.js. They are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle. Middleware can execute any code, make changes to the request and response objects, end the request-response cycle, or call the next middleware in the stack.
Think of middleware as a series of checkpoints that a request must pass through. At each checkpoint, you can inspect, modify, or even reject the request.
Types of Middleware
Section titled “Types of Middleware”Express middleware can be categorized into several types:
- Application-level middleware: Bound to the app object using
app.use()orapp.METHOD(). - Router-level middleware: Works the same as application-level, but is bound to an instance of
express.Router(). - Error-handling middleware: Has a special signature of
(err, req, res, next)to handle errors. - Built-in middleware: Standard middleware functions included with Express, such as
express.json()andexpress.static(). - Third-party middleware: Middleware available as packages on
npm, likehelmetormorgan.
Creating Custom Middleware
Section titled “Creating Custom Middleware”Let’s create a simple logger middleware that prints the timestamp and method for each incoming request.
Example: A Simple Request Logger
Section titled “Example: A Simple Request Logger”import express from 'express';
const app = express();const PORT = 3000;
// Custom logger middlewareconst requestLogger = (req, res, next) => { const timestamp = new Date().toISOString(); console.log(`[${timestamp}] ${req.method} ${req.originalUrl}`);
// This function call is crucial! It passes control to the next middleware. // Without it, the request would be left hanging. next();};
// Apply the middleware to all routesapp.use(requestLogger);
app.get('/', (req, res) => { res.send('Hello World!');});
app.get('/about', (req, res) => { res.send('This is the about page.');});
app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`);});Output
Section titled “Output”When you run this server and visit http://localhost:3000/, your console will show:
Server is running on http://localhost:3000[2023-10-27T10:30:00.123Z] GET /Path-Specific Middleware
Section titled “Path-Specific Middleware”You can apply middleware to a specific route or a group of routes by providing a path as the first argument to app.use().
const adminAuth = (req, res, next) => { // In a real app, you'd check for authentication credentials console.log('Admin auth check passed!'); next();};
// This middleware will only run for requests to /admin and its sub-routesapp.use('/admin', adminAuth);
app.get('/admin/dashboard', (req, res) => { res.send('Welcome to the Admin Dashboard');});Order of Middleware Matters
Section titled “Order of Middleware Matters”Middleware functions are executed sequentially, so the order in which you include them is critical. A request will pass through them one by one.
// Middleware 1: First to executeapp.use((req, res, next) => { console.log('First Middleware: Setting request time'); req.requestTime = Date.now(); next();});
// Middleware 2: Second to executeapp.use((req, res, next) => { console.log('Second Middleware: Logging request time'); console.log(`Request received at: ${new Date(req.requestTime).toLocaleTimeString()}`); next();});
app.get('/', (req, res) => { res.send(`Request was processed.`);});If a middleware function does not call next(), it must terminate the request-response cycle itself (e.g., by calling res.send() or res.json()). Otherwise, the request will be stuck.
Built-in and Common Third-Party Middleware
Section titled “Built-in and Common Third-Party Middleware”Express comes with powerful built-in middleware, and the npm ecosystem offers countless more for common tasks.
Built-in: express.json() and express.urlencoded()
Section titled “Built-in: express.json() and express.urlencoded()”Previously, the body-parser package was required to parse incoming request bodies. This functionality is now built directly into Express.
// To parse JSON-formatted request bodiesapp.use(express.json());
// To parse URL-encoded request bodies (e.g., from HTML forms)app.use(express.urlencoded({ extended: true }));
app.post('/api/users', (req, res) => { // req.body is now populated with the parsed data const newUser = req.body; console.log(newUser); res.status(201).json(newUser);});Third-Party: cookie-parser
Section titled “Third-Party: cookie-parser”This middleware parses the Cookie header and populates req.cookies with an object keyed by the cookie names.
# Installationnpm install cookie-parser
# Usageimport cookieParser from 'cookie-parser';app.use(cookieParser());
app.get('/set-cookie', (req, res) => { res.cookie('username', 'john.doe', { httpOnly: true }); res.send('Cookie has been set!');});
app.get('/read-cookie', (req, res) => { // Access the cookie from req.cookies const username = req.cookies.username; res.send(`Hello, ${username}!`);});Third-Party: morgan
Section titled “Third-Party: morgan”morgan is a popular HTTP request logger middleware. It’s more powerful than our custom logger and is highly configurable for production environments.
# Installationnpm install morgan
# Usageimport morgan from 'morgan';
// Use the 'dev' format for concise, color-coded logs during developmentapp.use(morgan('dev'));