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...
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?
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.
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;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.