Vivek
Vivek

Reputation: 15

Chaining of middleware in Express

I am writing APIs and wanted to understand what is a good way to add middleware shared by multiple routes. The middlewares does the same things in each route, like validating hosts/ip, validate user, etc. The req object gets loaded with other objects in each of the middlewares like req.host, req.ip, req.username etc.

    app.post("/route1", middleware1, middleware2, middleware3, middleware4);
    app.post("/route2", middleware1, middleware2, middleware3, middleware4);

    const middleware1 = (req, res, next) => {
     // does something to validate user
     req.username = "username"
     next();
    }
    const middleware2 = (req, res, next) => {
     // host validation
     req.host = "something modified in validation"
     next();
    }
    const middleware3 = (req, res, next) => {
     // checks for mac and ip
     req.mac = "mac addr"
     next();
    }
    const middleware4 = (req, res, next) => {
     res.send();
    }

Or something like this:


    app.post("/route1", middleware1);
    app.post("/route2", middleware1);


    const middleware1 = (req, res) => {
      // does something to validate user
      req.username = "username"
      middleware2(req, res);
    }
    const middleware2 = (req, res) => {
      // host validation
      req.host = "something modified in validation"
      middleware3(req, res);
    }
    const middleware3 = (req, res) => {
      // checks for mac and ip
      req.mac = "mac addr"
      middleware4(req, res);
    }
    const middleware1 = (req, res) => {
      res.send();
    }

Thanks.

Upvotes: 0

Views: 5030

Answers (3)

Suresh Prajapati
Suresh Prajapati

Reputation: 4457

You can specify multiple middlewares, see the app.use docs:

An array of combinations of any of the above.

You can create a file of all middlewares like -

middlewares.js

module.exports = [
  function(req, res, next){...},
  function(req, res, next){...},
  function(req, res, next){...},
  .
  .
  .
  function(req, res, next){...},
]

and as then simply add it like:

/*
you can pass any of the below inside app.use()
A middleware function.
A series of middleware functions (separated by commas).
An array of middleware functions.
A combination of all of the above.
*/
app.use(require('./middlewares.js'));

Note - Do this only for those middlewares which will be common for all such requests.

Upvotes: 0

Eslam Abu Hugair
Eslam Abu Hugair

Reputation: 1208

const express = require('express')
const { routesMiddleware } =require('./middlewares')
const { pureVaidationsFunctions1 } =require('./services')

const rout1 =express.Router()
const rout2 =express.Router()

const app = express()

app.use('/route1',route1)
app.use('/route2',route2)

// routesMiddleware a middleware to handle the execution of list of functions

// pureVaidationsFunctions1 list of funtions that `routesMiddleware` will consume
route1.post(routesMiddleware(pureVaidationsFunctions1))
route2.post(routesMiddleware(pureVaidationsFunctions2))

make sense?

Upvotes: 0

slebetman
slebetman

Reputation: 113876

Generally I wouldn't call middlewares directly from another middleware. It mixes responsibilities of middleware logic and where the middleware is used.

Express is much more configurable than you think though. You can also install common middlewares in common paths:

  1. If all routes use the middlewares:

    // How common middlewares are normally installed:
    app.post(middleware1);
    app.post(middleware2);
    app.post(middleware3);
    app.post(middleware4);
    
    // Alternative, less common way to do it:
    app.post(middleware1,middleware2,middleware3,middleware4);
    
  2. If only a specific pattern of urls use the middlewares:

    // Use a regexp:
    app.post(/route(1|2)/, middleware1, middleware2, middleware3, middleware4);
    
    // Or if you don't like regexp, use globs:
    app.post('route*', middleware1, middleware2, middleware3, middleware4);
    // Or a more specific glob pattern:
    app.post('route1?2?', middleware1, middleware2, middleware3, middleware4);
    
  3. If all url in a subpath use the middlewares. For example, lets say if all urls in /route/... use the middlewares:

    const route = express.Router();
    
    app.use('/route',route);
    route.post(middleware1);
    route.post(middleware2);
    route.post(middleware3);
    route.post(middleware4);
    

If none of the above appeal to you you can still use your second option but instead of calling middlewares inside each other you write a middleware to initialize middlewares:

function commonMiddlewares (req, res, next) {

    middleware1(req,res,function() {
        middleware2(req,res,function() {
            middleware3(req,res,function() {
                middleware4(req,res,next);
            });
        });
    });
}

Which can be written in a less nested way:

function commonMiddlewares (req, res, next) {
    function runMiddleware4 () {
        middleware4(req,res,next);
    }
    function runMiddleware3 () {
        middleware3(req,res,runMiddleware4);
    }
    function runMiddleware2 () {
        middleware2(req,res,runMiddleware3);
    }

    middleware1(req,res,runMiddleware2);
}

Upvotes: 3

Related Questions