101

I want to just verify something but have't been able to find anything in the Express docs or online regarding this (although I know it's a feature).

I could just test this out but I don't really have a nice template and would like to hear from the community.

If I define a route in express like such:

app.get('/', function (req, res) {
  res.send('GET request to homepage');
});

I can also define a middleware and load it directly, such as

middleware = function(req, res){
  res.send('GET request to homepage');
});

app.get('/', middleware)

However, I can also chain at least one of these routes to run extra middleware, such as authentication, as such:

app.get('/', middleware, function (req, res) {
  res.send('GET request to homepage');
});

Are these infinitely chainable? Could I stick 10 middleware functions on a given route if I wanted to? I want to see the parameters that app.get can accept but like mentioned I can't find it in the docs.

Anthony
  • 13,434
  • 14
  • 60
  • 80
  • 1
    Yes they are infinitely chainable, AFAIK Express takes the first argument to 'get' as the pattern match, and all subsequent arguments are middlewares. As coded your middleware will always send a response, so no following middlewares will ever be run. Use `function(req, res, next){ ... next() }` to yield to the next middleware in the chain. – Plato Aug 10 '15 at 20:28

3 Answers3

164

Consider following example:

const middleware = {
    requireAuthentication: function(req, res, next) {
        console.log('private route list!');
        next();
    },
    logger: function(req, res, next) {
       console.log('Original request hit : '+req.originalUrl);
       next();
    }
}

Now you can add multiple middleware using the following code:

app.get('/', [middleware.requireAuthentication, middleware.logger], function(req, res) {
    res.send('Hello!');
});

So, from the above piece of code, you can see that requireAuthentication and logger are two different middlewares added.

Ankur Soni
  • 5,725
  • 5
  • 50
  • 81
  • 7
    thanks was wondering if I could just pass in an array in there – Thabo Jun 11 '17 at 10:04
  • 1
    Hi - when using this method is it appropriate to add things to the req object for access in the later middlewares? For example, in the first: req.user = User.find... – James Trickey Sep 20 '17 at 09:39
81

It's not saying "infinitely", but it does say that you can add multiple middleware functions (called "callbacks" in the documentation) here:

router.METHOD(path, [callback, ...] callback)

...

You can provide multiple callbacks, and all are treated equally, and behave just like middleware, except that these callbacks may invoke next('route') to bypass the remaining route callback(s). You can use this mechanism to perform pre-conditions on a route then pass control to subsequent routes when there is no reason to proceed with the route matched.

As you can see, there's not distinction between a middleware function and the function that commonly handles the request (the one which is usually the last function added to the list).

Having 10 shouldn't be a problem (if you really need to).

Tushar Gupta - curioustushar
  • 58,085
  • 24
  • 103
  • 107
robertklep
  • 198,204
  • 35
  • 394
  • 381
  • 1
    Ok, thank you! You found the piece in the documentation that I couldn't. And no, I don't even really need to chain more than two but I just wanted to know how the API was structured. Thanks again! – Anthony Aug 10 '15 at 20:36
  • 1
    This totally needs to be more recognized by tutorials and the documentation. Thanks a bunch for this advice! – SeedyROM Jun 03 '19 at 10:41
5

Express version "express": "^4.17.1" or above

From the document: Series of Middleware

var r1 = express.Router();
r1.get('/', function (req, res, next) {
  next();
});

var r2 = express.Router();
r2.get('/', function (req, res, next) {
  next();
});

app.use(r1, r2);

Let's try a real life example:

tourController.js

 exports.checkBody = (req, res, next)=>{ // middleware 1
    if (!req.body.price){
        return res.status(400).json({
            status:'fail',
            message:'Missing price!!!'
        })
    }
    next();
  }

 exports.createTour = (req, res) => { // middleware 2
    tours.push(req.body);
    fs.writeFile(
      `${__dirname}/dev-data/data/tours-simple.json`,
      JSON.stringify(tours),
      (err) => {
        res.status(201).json({
          status: 'success',
          data: {
            tour: newTour,
          },
        });
      }
    );
  };

tourRouter.js

const express = require('express');
const tourController = require('./../controller/tourController')
const router = express.Router();

router.route('/')
.get(tourController.getAllTours)
.post(tourController.checkBody, tourController.createTour); 
//muliple Middleware in post route

module.exports = router //need this or the following step will break

app.js

const express = require('express');
const tourRouter = require('./route/tourRouter');
const app = express();

app.use(express.json());
app.use('/api/v1/tours', tourRouter);
module.exports = app;
SamWalker
  • 25
  • 1
  • 8
Rafiq
  • 8,987
  • 4
  • 35
  • 35