Dung (Donny) Nguyen

Senior Software Engineer

Middleware Functions in Express

In Express, middleware functions are functions that execute during the lifecycle of a request to the server. They sit between the client request and the server response, allowing us to manipulate requests, responses, and control what happens next in the application’s flow. Middleware is one of the core concepts in Express, and it enables a modular approach to handling various aspects of request processing, like authentication, logging, error handling, and data parsing.

How Middleware Works

  1. Request Processing Flow: When an incoming request is received, it passes through a stack of middleware functions defined in our Express app. Each middleware function has access to the request (req) and response (res) objects, along with the next function, which passes control to the next middleware.

  2. Calling next(): The next function is essential for the flow to continue. If a middleware function does not call next(), the request processing will stop at that point, and the response will not be sent to the client. This feature allows middleware to control the request lifecycle explicitly.

  3. Types of Middleware:

    • Application-Level Middleware: Defined directly on the Express app instance using app.use(), it applies to all routes or specific paths.
    • Router-Level Middleware: Attached to specific routers for modular route handling.
    • Error-Handling Middleware: Specialized middleware that takes four arguments (err, req, res, next) and handles errors that occur in the application.
    • Built-in Middleware: Express has built-in middleware like express.json() for parsing JSON request bodies.
    • Third-Party Middleware: Libraries like cors, morgan, and helmet add specific functionalities to Express apps.

Purpose of Middleware

Middleware allows us to handle cross-cutting concerns in a modular and reusable way. Here are some common uses:

Example of Middleware in Action

const express = require('express');
const app = express();

// Application-level middleware
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next(); // Pass control to the next middleware function
});

// Built-in middleware for parsing JSON
app.use(express.json());

// Route handler
app.get('/', (req, res) => {
  res.send('Hello, World!');
});

// Error-handling middleware
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

In this example:

  1. The first middleware logs every request.
  2. express.json() middleware parses incoming JSON payloads.
  3. A route handler serves the base route.
  4. The error-handling middleware handles any errors that occur, ensuring the app doesn’t crash.

Middleware in Express makes it easier to maintain clean, modular, and reusable code for complex request handling.