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

How to perform query caching in MySQL and how to solve failures

We all know that we need to understand the proper...

The current better way to make select list all options when selected/focused

During development, I encountered such a requireme...

MySQL paging query optimization techniques

In applications with paging queries, queries that...

JavaScript Advanced Custom Exception

Table of contents 1. Concept 1.1 What are errors ...

Solution to overflow:hidden failure in CSS

Cause of failure Today, when I was writing a caro...

Detailed tutorial on installing Docker on CentOS 7.5

Introduction to Docker Docker is an open source c...

How to install binary MySQL on Linux and crack MySQL password

1. Make sure the system has the required libaio s...

vue-cli4.5.x quickly builds a project

1. Install vue-cli npm i @vue/cli -g 2. Create a ...

Implementation of CSS3 3D cool cube transformation animation

I love coding, it makes me happy! Hello everyone,...

Analysis of product status in interactive design that cannot be ignored in design

In the process of product design, designers always...

MySQL select, insert, update batch operation statement code examples

In projects, batch operation statements are often...

Vue form input binding v-model

Table of contents 1.v-model 2. Binding properties...

Vue uses canvas to realize image compression upload

This article shares the specific code of Vue usin...

Sample code for html list box, text field, and file field

Drop-down box, text field, file field The upper p...