Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I combine Connect middleware into one middleware?

I have a few middlewares that I want to combine into one middleware. How do I do that?

For example...

// I want to shorten this...
app.use(connect.urlencoded())
app.use(connect.json())

// ...into this:
app.use(combineMiddleware([connect.urlencoded, connect.json]))

// ...without doing this:
app.use(connect.urlencoded()).use(connect.json())

I want it to work dynamically -- I don't want to depend on which middleware I use.

I feel like there's an elegant solution other than a confusing for loop.

like image 395
Evan Hahn Avatar asked Nov 28 '13 20:11

Evan Hahn


People also ask

Which Express method is used to add a middleware?

use() to add a middleware function to our Express application. Express will first execute function1 and then function2 . Middleware functions in Express are of the following types: Application-level middleware which runs for all routes in an app object.

What is middleware connect?

Middleware sits between an operating system and the applications that run on it. It is effectively software that provides a method of communication and data management between applications that would otherwise not have any way to exchange data -- such as with software tools and databases.

What is next middleware?

Next. js' middleware allows you to create functions that execute after a user's request is made and before the request is completed — in the middle of the two processes. This enables you to process a user's request and then modify the response by rewriting, redirecting, modifying headers, or even streaming HTML.


2 Answers

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);
      });
    };
  });
}
like image 192
Sanketh Katta Avatar answered Nov 06 '22 17:11

Sanketh Katta


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.

like image 28
vkurchatkin Avatar answered Nov 06 '22 17:11

vkurchatkin