salezica
salezica

Reputation: 77089

Express: composing middleware

I want to move a series of app.use() calls into its own module. The easiest way to encapsulate this is to expose a function(app) in the exports, but I feel that handing over the app object is too much of an opaque interface.

I would like to expose a middleware to be app.use()'d from outside the module. I need to chain/compose the middlewares used internally.

Is there a stylish way of doing this, or an alternative? What's the easiest way of going about it? Anything I should avoid?

Upvotes: 9

Views: 4646

Answers (3)

Bijou Trouvaille
Bijou Trouvaille

Reputation: 9474

This answer is a little late, but here it goes anyway...

// composedMiddleware.js
const express = require('express')
const ware1 = (req, res, next)=>{...}
const ware2 = (req, res, next)=>{...}
const router = express.Router()
router.use(ware1)
router.use(ware2)
export default router

// app.js
const composedMiddleWare = require('./composedMiddleware.js')
app.get('/something', (req, res, next)=>{...})
app.get('/something', composedMiddleWare)

If the code isn't self-explanatory, then just note that routers are also middleware. Or, to put it more precisely, "a router behaves like middleware itself, so you can use it as an argument to app.use()" ref.

Upvotes: 17

robertklep
robertklep

Reputation: 203534

Here's my take:

// app.js
...
app.use(require('./middleware')());
...

// middleware.js
var express    = require('express');    
module.exports = function() {
  var middleware = [
    // list of middleware that you want to have performed:
    function mymiddleware(req, res, next) {
      console.log('hello world');
      next();
    },
    express.logger('dev'),
    express.cookieParser(),
    express.static(__dirname)
  ];
  return function(req, res, next) {
    (function iter(i, max) {
      if (i === max) {
        return next();
      }
      middleware[i](req, res, iter.bind(this, i + 1, max));
    })(0, middleware.length);
  };
};

If you need access to the app in your custom middleware, you can access it through req.app or res.app.

Upvotes: 2

Michelle Tilley
Michelle Tilley

Reputation: 159135

Glancing through the code for Express (and Connect, on which it is based), it appears that calling use on a piece of middleware does not notify anything in any way, so there's really no way to compose things ahead of time without passing in app.

You could, however, do the composition at run time, e.g. the first time your middleware is called, compose some functions together and cache/call them.

Upvotes: 2

Related Questions