Lanbo
Lanbo

Reputation: 15672

Second router or middleware path in express.js

I have the usual middleware stack for my app:

  app.configure(function() {
    app.use(express.static(PUBLIC_DIR));
    app.use(express.favicon());
    app.use(express.bodyParser({
      keepExtensions: true,
      uploadDir: '/tmp/neighr'
    }));
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.session({
      secret: '***REDACTED***',
      store: sessionStore,
    }));
    app.use(express.csrf());
    app.use((require('connect-flash'))());
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(function(req, res, next) {
      app.locals({
        _csrf: req.session._csrf,
        url: req.url,
        user: req.user,
        authenticated: req.isAuthenticated(),
        messages: {
          info: req.flash('info'),
          error: req.flash('error'),
          success: req.flash('success')
        }
      });
      next();
    });
    app.use(app.router);
    app.use(express.logger());
    app.use(express.errorHandler());
  });

As you can see, the express.static is one of the first in the stack, so that static resources will be served without going through the entire session stuff which only makes loading times longer.

I do have, however, some dynamic data I'd like to serve without all the session stuff:

app.get('/avatar/:id', function(req, res) {
  var fid = res.params.id;
  /* load binary from database */
  res.send(data);
});

This route is within app.router, at the end of the stack. I would like to keep the way to declare this and other routes, but how can I get express to parse these before the session middleware?

There might be more such dynamic routes in the future, with more parameters.

Upvotes: 1

Views: 2802

Answers (1)

robertklep
robertklep

Reputation: 203231

Once you declare a route, Express inserts the router middleware into the middleware stack at that point, so if you were to declare a single route before loading the session middleware, all route requests would skip the session middleware:

app.get('/one', ...); // inserts `app.router` into the stack at this point
app.use(express.session(...));
app.get('/two', ...); // will skip the session middleware

There's two solutions I can think of: create your own middleware to handle the requests which shouldn't be passed through the session middleware, or explicitly set the session middleware for each route you want to run through it.

First solution:

app.use(function(req, res, next) {
  if (req.path.indexOf('/avatar/') === 0) {
    // parse out the `id` and return a response
  }
  next();
});

This obviously isn't very flexible.

Second solution:

// instantiate the session middleware:
var sessionMiddleware = express.session(...);

// default setup: insert the router before the session middleware:
app.use(app.router);
app.use(sessionMiddleware);

// Pass it explicitly to the route:
app.get('/two', sessionMiddleware, function(req, res) {
  ...
});

In your situation, where you also use Passport, you might want an array of middleware:

var authMiddleware = [
  express.session(...),
  passport.initialize(),
  passport.session()
];
app.get('/two', authMiddleware, ...);

Looking at how Express is implemented, I don't think it's possible to instantiate a second router (and get it to function properly).

Upvotes: 6

Related Questions