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
- Using Express Middleware (expressjs.com)
- Writing Express Middleware (expressjs.com)
- List of Common Express Middlewares (expressjs.com)
- Error handling in Express (expressjs.com)