bodokaiser
bodokaiser

Reputation: 15752

Expressjs: How to share route middleware accross routes

I have defined multiple route middleware and want to share them across multiple routes/controllers.

Here is my setup:

app.js requires ./routes/index.js:

// load fs module
var fs = require('fs');

// import routing files
module.exports = function(app){
    fs.readdirSync(__dirname).forEach(function(file) {
        if (file == "index.js") return;
        var name = file.substr(0, file.indexOf('.'));
        require('./' + name)(app);
    });
};

index.js loads all routes automaticly in the dir. A possible routes file can look like:

module.exports = function(app) {

    app.get('/contacts', function(req, res, next) {
       // routing stuff
    });

};

Now I got route middleware:

function isAuthenticated(req, res, next) {
    if (!req.session.authenticated) return next(new Error('user not authenticated'));
};

function loadUser(req, res, next) {
    var query = User.findById(req.session.user_id);
    query.populate('contacts');
    query.exec(function(err, user) {
        if (err) return next(err);
        req.user = user;
        next();
    });
}

which I want to use like:

var User = require('../models/user');

module.exports = function(app) {

    app.get('/contacts', isAuthenticated, loadUser, function(req, res, next) {
       res.json(req.user.contacts);
    });

};

I also would like to avoid requiring them accross all routing files.

A possible solution would also be:

// load fs module
var fs = require('fs');

var routeMiddleware = {
    loadUser: function(req, res, next) { // logic },
    isAuthenticated: function(req, res, next) { // logic },
};


// import routing files
module.exports = function(app){
    fs.readdirSync(__dirname).forEach(function(file) {
        if (file == "index.js") return;
        var name = file.substr(0, file.indexOf('.'));
        require('./' + name)(app, routeMiddleware);
    });
};

but I think not the best...

Upvotes: 5

Views: 6739

Answers (1)

Jonathan Ong
Jonathan Ong

Reputation: 20345

Personally I would declare shared middleware in the app, not in the controllers, i.e.:

routes/home.js:

module.exports = function(req, res, next) { \\ Code }

app.js:

app.get('/', thisMiddleware, thatMiddleware, require('./routes/home'))

You can also make a stack (array, not an object):

theseMiddlewares = [thisMiddleware, thatMiddleware]
app.get('/', theseMiddlewares, require('./routes/home'))

And if these middlewares are used on all routes except a few, you can do the following:

theseMiddlewares = function(req, res, next) {
  if (req.url.match(some_regex_for_urls_to_skip)) next()
  else {
    \\ do stuff...
    next()
  }
}

Now you can app.use(theseMiddlewares) that middleware, or if it needs to happen in a certain order relative to other middleware, you can use app.all('*', theseMiddlewares)

Upvotes: 13

Related Questions