How does Middleware work in Express?

The article has been translated. Link to original

This article is an adapted excerpt from the book “Express API Validation Essentials“It will teach you a complete API validation strategy that you can start using in your Express applications today.

__________________

The Express documentation tells us that “An Express application is essentially a series of calls to middleware functions.” At first glance, this sounds simple, but to be honest, middleware can be quite confusing. You are probably wondering:

  • Where is the correct place to add this middleware to my application?

  • When should I call the callback function nextand what happens when I do this?

  • Why is the order of use of middleware important?

  • How can I write my own error handling code?

The middleware pattern is fundamental to building Express applications, so you need to have a good understanding of what middleware is and how it works.

In this article, we’ll take a closer look at the middleware pattern. We’ll also look at the different types of Express middleware and how to combine them effectively when building applications.

Middleware template

In Express Middleware, this is a specific style of functionality that you configure for use by your application. They can execute whatever code you like, but they usually take care of handling incoming requests, sending responses, and handling errors. They are the building blocks of every Express application.

When you define a route in Express, the route handler function you specify for that route is the Middleware function:

app.get("/user", function routeHandlerMiddleware(request, response, next) {
    // execute something
});

(Example 1.1)

Middleware is flexible enough. You can tell Express to run the same middleware function on different routes, which will allow you to do things like general validation for different API endpoints.

Besides writing your own middleware functions, you can also install third-party middleware for use in your application. The Express documentation lists some popular middleware modules… On the npm a wide range of Express middleware modules are also available.

Middleware syntax

Here is the syntax for the middleware function:

/**
 * @param {Object} request - Express request object (commonly named `req`)
 * @param {Object} response - Express response object (commonly named `res`)
 * @param {Function} next - Express `next()` function
 */
function middlewareFunction(request, response, next) {
    // execute something
}

(Example 1.2)

Note: You may have noticed that I refer to req as request and res as response. You can name the parameters of your intermediate functions whatever you want, but I prefer to use clearer variable names because I find it easier for other developers to understand what your code is doing, even if they are not familiar with the Express framework.

When Express runs the middleware function, three arguments are passed to it:

  • Express request object (usually called req) is an extended instance of the Node.js built-in class http.IncomingMessage

  • Express response object (usually called res) is an extended instance of the Node.js built-in class http.ServerResponse

  • Express function next() – After the intermediate function has completed its tasks, it must call the function next()to transfer control to the next middleware. If you pass an argument to it, Express takes it as an error. It will skip any remaining non-error-handling middleware functions and start executing the error-handling middleware.

  • Middleware functions shouldn’t matter return… Any value returned by the middleware will not be used by Express.

Two types of Middleware

Regular middleware

Most of the Middleware features that you will be working with in an Express application are what I call “simple” middleware (there is no specific term for them in the Express documentation). They look like a function defined in the above middleware syntax example (example 1.2).

Here’s an example of a simple middleware function:

function plainMiddlewareFunction(request, response, next) {
    console.log(`The request method is ${request.method}`);

    /**
     * Ensure the next middleware function is called.
     */
    next();
}

(Example 1.3)

Middleware for error handling

  • Difference between middleware for error handling and the usual middleware is that the error handling middleware functions set four parameters instead of three, i.e. (error, request, response, next).

Here’s an example of a middleware function for handling errors:

function errorHandlingMiddlewareFunction(error, request, response, next) {
    console.log(error.message);

    /**
     * Ensure the next error handling middleware is called.
     */
    next(error);
}

(Example 1.4)

This intermediate error handling function will be executed when another intermediate function calls the function next() with an error object eg.

function anotherMiddlewareFunction(request, response, next) {
    const error = new Error("Something is wrong");

    /**
     * This will cause Express to start executing error
     * handling middleware.
     */
    next(error);
}

(Example 1.5)

Using middleware

The order in which the middleware is configured is very important. You can apply them at three different levels in your application:

  • Route level

  • Router level

  • Application layer

If you want a route (or routes) to handle errors it throws with error handling middleware, you must add it after you define the route.

Let’s take a look at what the middleware setup looks like at each level.

At route level

This is the most specific level: any middleware you configure at the route level will only work for that specific route.

app.get("https://habr.com/", someMiddleware, routeHandlerMiddleware, errorHandlerMiddleware);

(Example 1.6)

Router levelbut

Express lets you create objects Router… They allow you to restrict middleware usage to a specific set of routes. If you want the same middleware to run for multiple routes rather than all, then such objects can be very useful.

import express from "express";

const router = express.Router();

router.use(someMiddleware);

router.post("/user", createUserRouteHandler);
router.get("/user/:user_id", getUserRouteHandler);
router.put("/user/:user_id", updateUserRouteHandler);
router.delete("/user/:user_id", deleteUserRouteHandler);

router.use(errorHandlerMiddleware);

(Example 1.7)

At the application level

This is the least specific level. Any middleware configured at this level will run for all routes.

app.use(someMiddleware);

// define routes

app.use(errorHandlerMiddleware);

(Example 1.8)

Technically you can define multiple routes, call app.use(someMiddleware), then define a few other routes for which you want to run someMiddleware… I do not recommend this approach as it leads to a confusing and difficult-to-debug application structure.

You should only configure middleware at the application level if absolutely necessary, namely if you really need to run it for every route in your application. Every middleware function, no matter how small, requires a certain time to complete. The more middleware functions you need to run for a route, the slower requests to that route will run. It really grows as your application and configuration grows with more middleware. Try to restrict middleware to route or router levels whenever possible.

Summarizing

In this article, we learned about the Express middleware pattern. We also learned about the different types of middleware and how they can be combined to create an Express application.

If you want to read more about middleware, there are several tutorials in the Express documentation:

__________________

This article is an adapted excerpt from the book “Express API Validation Essentials“She teaches you a complete API validation strategy that you can start using in your Express applications today.

__________________

All codes in the images are available for copying here

The article was translated in anticipation of the start of the course “Node.js Developer”… Anyone who wants to learn more about the course and the learning process, we invite you to sign up for the Demo Day course, which will be held on June 28.

– BOOK UP FOR DEMO DAY COURSE

The article has been translated. Link to original

Similar Posts

Leave a Reply