I'm just getting comfortable with Node/Express. I'm attempting to create a basic REST api and I'm wondering how to deal with this dilemma.
Say I have a controller picking up a request (after authentication/ other middleware components have done their thing) that calls a model function to get some data, like this:
module.exports = function (router) {
router.get('/api/resource1', a_model.get_all);
};
The definition for the model would be something like:
exports.get_all = function (req, res, next) {
db.any('select * from resource_table')
.then(function (data) {
res.status(200).json({
status: 'success',
data: data,
message: 'Retrieved all the things.'
});
})
.catch(function (err) {
return next(err);
});
};
But now lets say I have another controller that also needs to call that model function, but also needs to do some other stuff with the data. E.G.
module.exports = function (router) {
router.get('/api/resource2', a_model.get_all, do_stuff_with_data);
};
The current state of a_model.get_all
will not allow do_stuff_with_data
to "do stuff" because it never calls next()
.
The issue is that if I just make it call next()
after it mutates res
, I get an error message saying: Error: Can't set headers after they are sent
when I hit /api/resource1
.
I tried if (next) { next(); }
, but that doesn't work either because there's always the error catching middleware at the bottom of the stack.
One possible solution would be to place a function equivalent to a NOP
at the end of my middleware chains, thus allowing my modules to always call next()
, but there has to be a better way, right?
First off, you can only have one middleware handler that sends the response. So, you have to architect your code so that the response to the incoming http request is sent in just one place and your code should be organized so that is very clear how and when that works.
Then, if you want to have multiple middleware handlers that contribute to a handler, then they can all examine the incoming req
object and can all contribute information to the res
object. Subsequent handlers can then use and access any of that information.
For example, one middleware handler could run a DB query, process that query, then put some results into the res
object as information that will then be available to subsequent middleware handlers during the processing of this request.
Another handler could further process the data some more, each passing it on to the next by calling next()
.
And, then finally a handler could send the actual response and that handler should not call next()
since it has now sent the response so the response needs to be done.
So, perhaps you need to just separate out your middleware (which just prepares data for an eventual response) from the code that actually sends the response. Your middleware needs to be in the appropriate order only if certain middleware handlers depend upon processing from prior middleware handlers.
Then, your code that actually uses the results of the prior middleware processing to send the final response has to be after the other middleware. Usually this is a specific route rather than a middleware handler, but there are cases where middleware might send the final response.