How does Node.js Middleware Work?

What is Express middleware?

  • Middleware literally means anything you put between one layer and another layer of software.
  • Express middleware is a function that executes during the life of a request to an Express server.
  • Each middleware has access to all the HTTP requests and responses to which it is attached.
  • Alternatively, the middleware can terminate the HTTP request or pass it to another middleware function with next. This “chain” of middleware allows you to partition your code and create reusable middleware.

Requirements for writing Express middleware

You need to install something to create, use, and test Express middleware. Node and NPM are needed first. To ensure it is installed, you can run:

npm -v && node -v

You should see the Node and NPM versions installed. If something goes wrong, you need to install Node . All examples should be used under Node ver 8+ and NPM ver 5+.

This article uses Express 4.x. This is important because of major changes from 3.x to 4.x.

Express Middleware: Basic

First we use Express’s most basic built-in middleware. Create a new project and initialize it with npm …

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?

Suppose you are using Node.js and Express to run a web application on a web server . In this application, you need to log in to certain pages.

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

Middleware functions are an ideal place to modify the req and res objects with related information. For example, users log in, you can get detailed information from its user database, and then these details are stored in res.user the.

What does a middleware function 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 do not want to execute other code, do not call this 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 forward or by using multiple arrays in the middleware app.use to link call middleware:

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

After Express receives the request, each middleware that matches the request will run in the initialization order until there is a terminating operation.

This is image title

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

Express middleware types

  • 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 uses the express.Router class to create modular, installable route processing. The routing 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 simply ends the response without invoking subsequent middleware or routing 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 features:

  • express.static Provide static resources such as HTML files, images, etc.
  • express.json The payload parses the incoming request in JSON.
  • express.urlencoded Parse incoming URL-encoded payload requests.

Error handling middleware

Error handling middleware always takes four parameters (err, req, res, next). You must identify it as an error-handling middleware function by providing four parameters. It must be specified even if you don’t need to use the next object. Otherwise, the next object will be interpreted as regular middleware and will not be able to handle errors. The basic signature looks like this:

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, I checked the res.headersSent property. This just checks if the response has sent the header to the client. If not, it will send HTTP 500 status and error messages to the client.

Example 2:

You can also link 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 if a 404 (not found) error is 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 is 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 only logs errors, if no response is sent, it sends the error httpStatusCode (or HTTP 500 status if not provided) and renders the “UnknownError” template.

Third-party-level middleware

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

Example: When the body-parser processing request Content-Type header, all intermediate filling body will use the parsed req.body attribute.

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')
})

to sum up

Middleware functionality is a great way to run code on every request or 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.

#nodejs #express #nodejs-middleware

How does Node.js Middleware Work?
17.20 GEEK