How do I combine Connect middleware into one middleware?
Express accepts arrays for app.use
if you have a path:
var middleware = [connect.urlencoded(), connect.json()];
app.use('/', middleware)
However, if you want a generic combineMiddleware
function, you can build a helper easily without any additional libraries. This basically takes advantage of the fact that next
is simply a function which takes an optional error:
/**
* Combine multiple middleware together.
*
* @param {Function[]} mids functions of form:
* function(req, res, next) { ... }
* @return {Function} single combined middleware
*/
function combineMiddleware(mids) {
return mids.reduce(function(a, b) {
return function(req, res, next) {
a(req, res, function(err) {
if (err) {
return next(err);
}
b(req, res, next);
});
};
});
}
If you like fancy stuff, here is one of possible solutions:
var connect = require('connect')
var app = connect()
function compose(middleware) {
return function (req, res, next) {
connect.apply(null, middleware.concat(next.bind(null, null))).call(null, req, res)
}
}
function a (req, res, next) {
console.log('a')
next()
}
function b (req, res, next) {
console.log('b')
next()
}
app.use(compose([a,b]))
app.use(function (req, res) {
res.end('Hello!')
})
app.listen(3000)
Here is what it does: compose
function takes array of middleware and return composed middleware. connect
itself is basically a middleware composer, so you can create another connect app with middlewares you want: connect.apply(null, middleware)
. Connect app is itself a middleware, the only problem is that it doesn't have a next()
call in the end, so subsequent middleware will be unreachable. To solve that, we need another last
middleware, which will call next
: connect.apply(null, middleware.concat(last))
. As last only calls next
we can use next.bind(null, null)
instead. Finally, we call resulting function with req
and res
.
Old question, but the need is still frequent for all the things using middlewares, like connect, express or custom made req/res/next patterns.
This is a very elegant and purely functional solution:
File ./utils/compose-middleware.js:
function compose(middleware) {
if (!middleware.length) {
return function(_req, _res, next) { next(); };
}
var head = middleware[0];
var tail = middleware.slice(1);
return function(req, res, next) {
head(req, res, function(err) {
if (err) return next(err);
compose(tail)(req, res, next);
});
};
}
module.exports = compose;
The final result of the compose(middlewareList)
is a single middleware that encapsulates the whole chain of middleware initially provided.
Then simply import it and use like this:
File app.js:
var connect = require('connect');
var compose = require('./utils/compose-middleware');
var middleware = compose([
connect.urlencoded(),
connect.json()
]);
var app = connect();
app.use(middleware);