Skip to content

Instantly share code, notes, and snippets.

@Frost
Last active January 3, 2016 14:29
Show Gist options
  • Select an option

  • Save Frost/8476511 to your computer and use it in GitHub Desktop.

Select an option

Save Frost/8476511 to your computer and use it in GitHub Desktop.

Express.js nested apps and routing

So... Say we are building this API in express.js, and it's supposed to have these routes:

/v1
   /ping
   /foo
       /bar
       /baz
/v2
   /ping

... and so on...

First iteration: stupidly naive

One way of registering these routes would be to have one single app.js file like this:

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

app.get("/v1/ping", function(req, res) { ... });
app.get("/v1/foo/bar", function(req, res) { ... });
app.get("/v1/foo/baz", function(req, res) { ... });
app.get("/v2/ping", function(req, res) { ... });

app.listen(4711);

This gets tedious after a while, and maybe you don't want to mix the routes for different versions, I mean, namespacing is generally kinda neat, right?

Second iteration: Split stuff into separate files!

Ok, well, in that case, you can define the different API versions in separate files, and then registering them, like so:

// app.js
var express = require('express'),
    v1 = require('./v1'),
    v2 = require('./v2'),
    app = express();

v1.register(app);
v2.register(app);

app.listen(4711);

// v1.js
exports.register = function(app) {
  app.get("/v1/ping", function(req, res) { ... });
  app.get("/v1/foo/bar", function(req, res) { ... });
  app.get("/v1/foo/baz", function(req, res) { ... });
}

// v2.js
exports.register = function(app) {
  app.get("/v2/ping", function(req, res) { ... });
}

I don't like that either, because I don't like injecting my root app into the sub apps.

Third iteration: Actual sub-apps!

Now, as it happens, express apps can be mounted as sub-apps to other express apps, since they basically just are a bunch of middleware.

We can now do this:

// app.js
var express = require('express'),
    v1 = require('./v1'),
    v2 = require('./v2'),
    app = express();

app.use('/v1', v1);
app.use('/v2', v2);

app.listen(4711);

// v1.js
var express = require('express'),
    foo = require('./foo'),
    app = express();

app.use('/foo', foo);
app.get('/ping', function(req, res) { res.send("pong"); });

module.exports = exports = app;

// v2.js
var express = require('express'),
    app = express();

app.get('/ping', function(req, res) { res.send("pong"); });

module.exports = exports = app;

// v1/foo.js
var express = require('express'),
    app = express();

app.get("/bar", function(req, res) { res.send("bar"); });
app.get("/baz", function(req, res) { res.send("baz"); });

module.exports = exports = app;

Bonus: use express.Router directly

When you are at the bottom of your route tree, you can use express.Router instead of creating an express app at each level. I believe this is a bit more lightweight.

When using the router directly, you create an instance of express.Router and export that, and then mount it with app.use('/sub', subAppThatUsesRouter.middleware).

Here's an example of that, with v1.js and v1/foo.js from above.

// v1.js
var express = require('express'),
    foo = require('./foo'),
    app = express();

app.use('/foo', foo.middleware);
app.get('/ping', function(req, res) { res.send("pong"); });

module.exports = exports = app;

// v1/foo.js
var express = require('express'),
    router = new express.Router();

router.get("/bar", function(req, res) { res.send("bar"); });
router.get("/baz", function(req, res) { res.send("baz"); });

module.exports = exports = router;

Other stuff to do might include moving v1.js to v1/index.js, if you prefer to put all your nesting in subdirectories.

The rest of the files in this gist are a working example based on this last iteration.

var express = require('express'),
v1 = require('./v1'),
v2 = require('./v2'),
app = express();
app.use('/v1', v1);
app.use('/v2', v2);
app.listen(4711);
var express = require('express'),
router = new express.Router();
router.get("/bar", function(req, res) { res.send("bar!"); });
router.get("/baz", function(req, res) { res.send("baz!"); });
module.exports = exports = router;
var express = require('express'),
foo = require('./v1-foo'),
app = express();
app.use('/foo', foo.middleware);
app.get('/ping', function(req, res) { res.send("pong"); });
module.exports = exports = app;
var express = require('express'),
app = express();
app.get('/ping', function(req, res) { res.send("pong"); });
module.exports = exports = app;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment