Detailed explanation of how Node.js middleware works

Detailed explanation of how Node.js middleware works

What is Express middleware?

  • Middleware literally means anything you put between one layer of software and another.
  • Express middleware are functions that are executed during the lifecycle of a request to an Express server.
  • Each middleware has access to the HTTP requests and responses of all routes it is attached to.
  • Additionally, middleware can terminate the HTTP request or pass it to another middleware function using next. This "chaining" of middleware allows you to compartmentalize your code and create reusable middleware.

Requirements for writing Express middleware

You need to install a few things to create, use, and test Express middleware. First you need Node and npm. To make sure it is installed, run:

npm -v && node -v

You should see the installed versions of Node and NPM. If you get an error, you need to install Node. All examples should be used with Node ver 8+ and NPM ver 5+.

This article uses Express version 4.x. This is important because there are breaking changes from version 3.x to version 4.x.

Express Middleware: The Basics

First we use the most basic built-in middleware of Express. Create a new project and npm initialize it...

npm init
npm install express --save

Create server.js and paste the following code:

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

app.get('/', (req, res, next) => {
  res.send('Welcome Home');
});

app.listen(3000);

What problems does middleware solve? Why use it?

Assume that you are running a web application using Node.js and Express on a web server. In this app, you need to log in on some pages.

When a web server receives a request for data, Express provides you with a request object that contains information about the user and the data they are requesting. Express also gives you access to the response object, which you can modify before the web server responds to the user. These objects are often shortened to req, res.

Middleware functions are the ideal place to modify the req and res objects with relevant information. For example, once a user logs in, you can fetch their user details from the database and then store those details in res.user.

What do middleware functions look like?

async function userMiddleware (req, res, next) {
    try {
        const userData = await getUserData(req.params.id); //see app.get below

        if(userData) {
                req.user = userData;
                next();
        }
    } catch(error) {
        res.status(500).send(error.message); //replace with proper error handling
    }
}

If an error occurs and you don't want other code to execute, then don't call the function. Remember to send a response in this case, otherwise the client will wait for the response until it times out.

var app = express();

//your normal route Handlers
app.get('/user/:id', userMiddleware, userController);

Middleware Chain

You can chain middleware in your middleware array or by using multiple app.use calls:

app.use(middlewareA);
app.use(middlewareB);
app.get('/', [middlewareC, middlewareD], handler);

When Express receives a request, each middleware that matches the request will be run in the order in which it was initialized until there is a termination action.

So if an error occurs, all middlewares for handling errors will be called in order until one of them no longer calls the next() function call.

Types of Express middleware

  • Router-level middleware, such as router.use
  • Built-in middleware, such as: express.static, express.json, express.urlencoded
  • Error handling middleware, for example: app.use(err, req, res, next)
  • Third-party middleware, such as bodyparser, cookieparser
  • Router-level middleware
  • express.Router Use the express.Router class to create modular, installable routing handlers. A router instance is a complete middleware and routing system. You can use middleware for logging, authentication, etc. As shown below, to record the user's latest activity and parse the authentication header, use it to determine the currently logged in user and add it to the Request object. This function is executed every time the program receives a request. If there is an error, it will just terminate the response without calling subsequent middleware or route processing.
var router = express.Router()
Load router-level middleware by using the router.use() and router.METHOD() functions.
The following example creates a router as a module, loads a middleware function in it, defines some routes, and mounts the router module on a path in the main app.
var express = require('express');
var router = express.Router();

// a middleware function with no mount path. This code is executed for every request to the router
// logging
async function logMiddleware (req, res, next) {
    try {
         console.log(req.user.id, new Date());
     next();
    } catch() {
        res.status(500).send(error.message);
    }
}
// authentication
    async function checkAuthentication(req, res, next) => {
// check header or url parameters or post parameters for token
const token = req.body.token || req.query.token || req.headers['x-access-token'] || req.headers['authorization'];
      if (token) {
        try {
            // verifies secret
            req.decoded = await jwt.verify(token, config.secret)

            let checkUser = await authenticateTokenHelper.getUserDetail(req);

            // if everything is good, save to request for use in other routes
                if (checkUser) {
                        req.user = req.decoded
                        next()
                } else {
                    return res.status(403).json({ 
                    message: responseMessage.noAuthorized 
                    })
                }
        } catch (err) {
            return res.status(401).json({ message: responseMessage.invalidToken })
        }
  } else {
    // if there is no token
    return res.status(400).json({ message: responseMessage.invalidRequest })
  }
}
router.use(logMiddleware);
    router.get('/user, checkAuthentication, handler);

Built-in middleware

Express has the following built-in middleware functions:

  • express.static serves static resources such as html files, images, etc.
  • The express.json payload parses the incoming request with JSON.
  • express.urlencoded parses incoming requests with URL-encoded payloads.

Error handling middleware

Error handling middleware always takes four arguments (err, req, res, next). You must identify it as an error handling middleware function by providing four arguments. Even if you don't need to use the next object, you must specify it. Otherwise the next object will be interpreted as regular middleware and will not be able to handle errors. The basic signature is as follows:

app.use(function (err, req, res, next) {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

Example 1:

app.get('/users', (req, res, next) => {
  next(new Error('I am passing you an error!'));
});
app.use((err, req, res, next) => {
  console.log(err);    
  if(!res.headersSent){
    res.status(500).send(err.message);
  }
});

In this case, the error handling middleware at the end of the pipeline will handle the error. You may also notice that I checked the res.headersSent property. This just checks if the response has already had the headers sent to the client. If not, it sends an HTTP 500 status and an error message to the client.

Example 2:

You can also chain error handling middleware. Different types of errors are usually handled differently:

app.get('/users, (req, res, next) => {
  let err = new Error('I couldn't find it.');
  err.httpStatusCode = 404;
  next(err);
});

app.get('/user, (req, res, next) => {
  let err = new Error('I'm sorry, you can't do that, Dave.');
  err.httpStatusCode = 304;
  next(err);
});

app.use((err, req, res, next) => {
   // handles not found errors
  if (err.httpStatusCode === 404) {
    res.status(400).render('NotFound');
  }
   // handles unauthorized errors 
  else if(err.httpStatusCode === 304){
    res.status(304).render('Unauthorized');
  }
    // catch all
   else if (!res.headersSent) {
     res.status(err.httpStatusCode || 500).render('UnknownError');
  }
  next(err);
});
  • In this case, the middleware checks whether a 404 (not found) error was thrown. If it is, it renders the "NotFound" template page and then passes the error to the next item in the middleware.
  • The next middleware checks if a 304 (unauthorized) error was thrown. If it is, it will render the "Unauthorized" page and pass the error to the next middleware in the pipeline.
  • Finally, the "catch all" error handling simply logs the error, and if no response is sent, it sends the wrong httpStatusCode (or HTTP 500 status if none is provided) and renders the "UnknownError" template.

Third-party middleware

In some cases we will add some additional functionality to the backend. Install the Node.js module to get the required functionality, then load it into your application at the application level or at the router level.

Example: When body-parser processes the Content-Type request header, all middlewares will populate the req.body property with the parsed body.

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())
app.post('/save',(req,res)=>{
    res.json({
        "status":true,
         "payload":req.body
    })
}
app.listen(3000,(req,res)=>{
    console.log('server running on port')
})

Summarize

Middleware functions are a great way to run code on every request or on every request for a specific route and take action on the request or response data. Middleware is an important part of modern web servers and is very useful.

The above is a detailed explanation of how Node.js middleware works. For more information about Node.js middleware, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Parsing of body-parser, a commonly used middleware for Express in Nodejs
  • In-depth understanding of Express middleware in nodejs
  • Detailed explanation of node-images, the middleware for processing images in nodejs
  • Nodejs development - express routing and middleware
  • NodeJS learning notes: Connect middleware application example
  • NodeJS learning notes: Connect middleware module (Part 2)
  • NodeJS learning notes: Connect middleware module (I)
  • Nodejs implements blacklist middleware design
  • Detailed explanation of using node.js middleware express-session

<<:  How to set default value for datetime type in MySQL

>>:  Detailed steps for installing Harbor, a private Docker repository

Recommend

Summary of how to modify the root password in MySQL 5.7 and MySQL 8.0

MySQL 5.7 version: Method 1: Use the SET PASSWORD...

Html easily implements rounded rectangle

Question: How to achieve a rounded rectangle usin...

How to reset the root password of Mysql in Windows if you forget it

My machine environment: Windows 2008 R2 MySQL 5.6...

How to set up vscode remote connection to server docker container

Table of contents Pull the image Run the image (g...

Detailed explanation of MySQL data grouping

Create Group Grouping is established in the GROUP...

In-depth understanding of Vue-cli4 routing configuration

Table of contents Preface - Vue Routing 1. The mo...

JavaScript Canvas implements Tic-Tac-Toe game

This article shares the specific code of JavaScri...

SQL implementation LeetCode (176. Second highest salary)

[LeetCode] 176. Second Highest Salary Write a SQL...

How InnoDB implements serialization isolation level

Serialization implementation InnoDB implements se...

React Native environment installation process

react-native installation process 1.npx react-nat...

Detailed explanation of whereis example to find a specific program in Linux

Linux finds a specific program where is The where...

Detailed explanation of several ways to export data in Mysql

There are many purposes for exporting MySQL data,...

Summary of Common Letters in Unicode

Most of the earliest computers could only use ASC...

Example of how to install nginx to a specified directory

Due to company requirements, two nginx servers in...