Search code examples
node.jsexpressconcurrencythread-safetymiddleware

Using Express middleware for per-request module configuration?


Let's say every request to my application contains a MAGIC header, and I want to inject that header value somewhere, without updating all of my request methods. Sounds like it's a job for middleware, right?

But will this be thread-safe? Is there a way to do this using Express middleware in a world where multiple requests could be in flight at the same time?

In other words, I'm asking if the Express middleware in the example code is setting a global shared variable or if each request is handled by an independent thread where myconfig is an isolated copy for each single request.

Example code:

var assert = require('assert');
var sleep = require('sleep');

var express = require('express');
var app = express();

var myconfig = {};

app.use(function(req, res, next) {
  myconfig.MAGIC = req.headers['MAGIC'];
  next();
});

app.get('/test', function(req, res) {
  // Pause to make it easy to have overlap.
  sleep(2);
  // If another request comes in while this is sleeping,
  // and changes the value of myconfig.MAGIC, will this
  // assertion fail?
  // Or is the copy of `myconfig` we're referencing here
  // isolated and only updated by this single request?
  assert.equal(myconfig.MAGIC, req.headers['MAGIC']);
});

Solution

  • Any middleware function will be executed for each request. When using middleware to set the value of something, it is typically a good idea to set it in app.locals or res.locals, depending on how you want the data to persist. Here is a good comparison of the two: https://stackoverflow.com/a/14654655/2690845

    app.use(function(req, res, next) {
      if (req.headers['MAGIC']) {
        app.locals.MAGIC = req.headers['MAGIC'];
      }
      next();
    });
    ...
    app.get('/test', function(req, res) {
      assert.equal(app.locals.MAGIC, req.headers['MAGIC']);
    });