Skip to content

Express Middleware in Node.js

Express middleware is code written that executes during a request/response cycle in Node.js. It’s commonly used to add functionality, or to provide features to Express like user authentication or caching to your application. Express itself is essentially a collection of “middlewares”. Understanding how middleware works, how to use them, and how to create your own is an important part of working with Express.

By the end of this tutorial, you should be able to:

  • Understand how Node.js Express middleware works
  • Understand the purpose of Express middleware
  • Know how to add middleware to your server
  • Create your own middleware to add custom functionality to Express

Goal

Understand how middleware works in Express and how to use it to add functionality to Express

Prerequisites

Watch: Express Middleware in Node.js

What is middleware?

Middleware is code that executes during the lifecycle of the request/response cycle and has access to the Request and Response objects.

You can look at them almost as plugins. They can be dropped into your application without you needing to change much else, and can augment your Request and Response objects or perform any other kind of logic while being an encapsulated piece of standalone code.

Express itself is essentially a collection of middleware plus routing capabilities. This is a powerful and flexible pattern. You can create your own middleware or add in any that have been published by others to extend your application’s capabilities.

Anatomy of a middleware

A middleware function takes up to three specific arguments, req, res, and next:

function myMiddleware(req, res, next) {
// run whatever code you need
console.log("Received a request...");
// call next to pass control to the next middleware
next();
}

The three parameters are the incoming Request object, the Response object, and next. Calling next() without any arguments signals that this middleware has finished successfully, and hands over control to the next middleware in the stack.

If an error occurred, pass the error as the first argument to next and Express will skip running the next middlewares and route handlers and proceed straight to the first error handler middleware. We cover error handler middlewares later in the tutorial.

If you forget to call next() or don’t end the request by sending back a response with res, the request will hang and never complete. This is a very common bug, so make sure you’re calling next() to trigger the next middleware if you didn’t send a response.

Using middleware

Middleware can be registered at a few different places in your application. If you want to run a particular middleware for all requests that come into the server, you can add it at the beginning of your Express application.

To use middleware, you register it with your application. You can register middleware with different levels of specificity to determine when/where it is run. The most broad is to register a middleware to run for every request the server receives. To do that, you pass the middleware function to app.use.

An example of this is body-parser, perhaps the most widely known and used Express middleware. It’s used to parse the incoming payload of a request into a JavaScript object and add it to the req object under req.body. This allows any other routes or middleware that come later to access the data sent in the request body. Instead of having to write this logic yourself, or duplicate it for every route, you can npm install body-parser and add the functionality to your server in one place.

const bodyParser = require("body-parser");
app.use(bodyParser.json());

You can also register middleware to run for all HTTP Methods sent to a specific route, by passing a path and middleware function to app.use:

const bodyParser = require("body-parser");
app.use("/test", bodyParser.json());

Finally, you can specify middleware for a specific route handler by adding it as an argument before the handler:

const bodyParser = require("body-parser");
app.get("/test", bodyParser.json(), (req, res) => {
return response.json({ status: "ok" });
});

Middlewares are run sequentially in the order they are registered.

For example, if we register a simple logging middleware which logs the req.body before we register body-parser, the logging middleware will run before the body has been parsed:

app.use(function(req, res, next) {
console.log("Request Body: ", req.body);
next();
});
app.use(bodyParser.json());

Any requests to the server would log Request body: undefined because req.body isn’t available due to the logging middleware running before body-parser. Registering the body-parser middleware before the logging middleware would fix this.

Error-handling middleware

Error handling middleware is very slightly different from regular middleware. To understand error handling middleware it’s important to understand error handling in Express in general.

Here are couple of things to keep in mind:

First, error handling middleware is typically registered after your routes so it can catch any errors that occurred while handling the request.

Second, and most importantly, error handling middleware takes 4 arguments: the first argument will be the error that occurred (often called err), and then the familiar arguments of req, res, and next. Accepting 4 arguments is how Express knows this is an error-handling middleware.

function handleAllErrors(err, req, res, next) {
// handle the error and determine what kind of response to send
console.log(err);
res.status(err.httpStatusCode || 500).send("Uh oh! An error occurred");
}

Creating error-handling middleware allows you to centralize error handling and sending error responses back to clients in one place in your application.

Recap

In this tutorial we discussed the basics of Express middleware and how to use it in our applications. Middleware adds functionality to an Express server in a flexible way. A middleware function normally takes three arguments: req, res, and next, and helps us run code during the lifecycle of a request. We learned how to register middleware with our application, either using app.use or registering it with a route handler. We also learned that error-handling middleware helps catch and handle errors that occur when handling requests, and takes an extra err argument compared to other middleware.

Further your understanding

  • Can you imagine how a middleware could be used to read the cookies sent with a request? How could your server use the information stored in a cookie?
  • Check out some popular middleware maintained by the Express team to get an idea of how middleware can be used in your application.
  • What are some benefits of using a middleware from the community to accomplish a task instead of creating your own?

Additional resources