What's the preferred architecture for cooperating middleware?

If I've created a database-backed routing middleware that checks for some data, and I want it to now pass through to a view/render middleware, what's my best approach?

Should I:

  • Attach my fetched data to the request object and set up my rendering layer as the next in the chain?
  • Directly call the rendering layer as if my own router was calling it like middleware?
  • Perhaps some other suggestion?

I'm looking for some general architecture advice that might help me ensure that each component of functionality I create doesn't end up being unmaintainable and large. Some things I've read have favoured breaking things into as many modules as I can, which makes me think the two options above might be good.

But perhaps one is better or there's something I'm missing?

If you're using express routes, a reliable architecture that encourages reuse and simplicity looks like:

app.use(errorHandler); // errorHandler takes 4 arguments so express calls it with next(err)
app.get('/some/route.:format?', checkAssumptions, getData, sendResponse);

...where checkAssumptions, getData, and sendResponse are just examples - you can make longer or shorter route chains depending on your application's needs. Such functions might look like:

function checkAssumptions(req, res, next) {
  if (!req.session.user) return next(new Error('must be logged in'));
  return next();
}

function getData(req, res, next) {
  someDB.getData(function(err, data) {
    if (err) return next(err);
    // now our view template automatically has this data, making this method reusable:
    res.localData = data;
    next();
  });
}

function sendResponse(req, res, next) {
  // send JSON if the user asked for the JSON version
  if (req.params.format === 'json') return res.send(res.localData);

  // otherwise render some HTML
  res.render('some/template');
}