Bootstrap Your Express.js App: Conditional Middleware

Adding a middleware to Express is easy, but it gets tricky when you have to load them conditionally. For instance, having a request logger is very handy during development, but you do not want it in production. Or you might want to turn off the ACL locally to ease testing. In our case, we wanted to add extra administration functionality only to a specific installation, not on all instances.

We organise our middleware into groups like core, cors, session, database, acland so forth. These groups consist of configurations of one or more middleware. For instance the core:

core: (app) => {
  // Security
  console.log(':: Helmet');
  app.use(Helmet());

  // Compression
  console.log(':: Compression');
  app.use(Compression());

  // Proper error messages
  console.log(':: Boom');
  app.use(Boom());

  // json body parser
  console.log(':: json body parser');
  app.use(BodyParser.json());
},

 

Bootstrap.js

The Bootstrap class holds all the middleware groups and their configurations. The constructor simply receives the Express app, then takes the pre-defined middleware list from the config file and executes the matching functions in the right order.

import * as Config from 'config';
const expressConfig = Config.get('express') as ExpressConfig;

class Bootstrap {

  constructor(app) {
    let self = this;
    // Taking the list from the the config file
    let bootstrap = expressConfig.bootstrap;  
    for (var module of bootstrap) {
      self.middleware[module](app);
    }
  }
  
  middleware = {
    /**
     * Core components, such as security, compression, responses, body parser.
     */
    core: (app) => {
      // Security
      app.use(Helmet());
      // Compression
      app.use(Compression());
      // Proper error messages
      app.use(Boom());
      // json body parser
      app.use(BodyParser.json());
    },

    /**
     * CORS settings.
     * This is configurable in the config files.
     */
    cors: (app) => {
      var corsOptions = {
        credentials: true,
        origin: expressConfig.allowOrigin,
      };
      app.use(CORS(corsOptions));
      app.options('*', CORS(corsOptions));
    },

    /**
     * Session management. Configure your settings here.
     * e.g. RedisStore
     */
    session: (app) => {
      const Session = require('express-session');
      app.use(Session());
    },
  };
}

export {Bootstrap};

 

Configuration

node-config is pretty standard. It allows you to create configuration files for every instance you have: development, staging, production.

In these config files you can define the middleware groups you want to load and their order.

"bootstrap": [
  "core",
  "cors",
  "session",
  "geoIP",
  "requestQueryParser",
  "requestLogger",
  "acl",
  "database",
  "routes",
  "admin"
]

Adding Bootstrap

Then you just pass your Express app to the Bootstrap logic.

import * as Express from 'express';
let app = Express();

import {Bootstrap} from './api/bootstrap';
new Bootstrap(app);