Search code examples
javascriptnode.jsexpresshttp-headersmiddleware

Express: calling next() after json() - Middlewares


Building a REST API with NodeJs and Express: my goal is to implement the 2 simplest Middlewares:

  1. The first one is going to log the incoming request
  2. The second one is going to log the processed response (which is a JSON)

The first middleware (in app.js)

function logReqMiddleware(req, res, next) {
  log.info('>>> %s at %s', req.method, req.path);
  next();
}

The second middleware (in app.js)

function logResponseMiddleware(req, res, next) {
  log.info('<<< %s (%s)', JSON.stringify(res), res.status);
  next();
}

The controller function (in apiController.js)

export var router = express.Router();
router.get('/', foo);

function foo(req, res, next) {
  res.status(200).json({ stupidExample: true });
  next();
}

Building the app (app.js)

var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(logReqMiddleware);
app.use('/api', apiController.router);
app.use(logResponseMiddleware);
var server = app.listen(3000, function(){ log.info('running'); });

Now, making a request at localhost:3000/api says: can't set headers after they are sent; this is the related super cool response my question is, is it incompatible to write json data with json() and adding the second middleware? How can I solve this?


Solution

  • Don't call next() inside logResponseMiddleware. There's nothing else to do, so calling next() is probably sending you into express's default 404 handler which is trying to respond with a default status and body.

    Aside: JSON.stringify(res) is not what you want. res is an object instance representing the response (lots of methods, internal state properties, etc). It is not the response body content string. As the res is a writeable stream, it's not going to keep the response body content around for you to log, it's just going to try to send it over the HTTP connection.