Whenever I need to build a quick web application I turn to ExpressJS. It is a fast, minimal, easy to configure web server that puts the E in MEAN). I wanted to build a REST API for a hobby app and found that the docs for how to nest routes are relatively few (see blog, stackoverflow answer). Combining these two resources, I learned a simple method for keeping your routes separate while creating a nested routing structure.
The Plan
I want to create routes that look like these:
/foo
/foo/bar
/foo/42
/foo/42/baz
/foo/42/baz/123
Using the express-generator and a few simple commands, you can get your server up and running fast:
$ npm install express-generator -g
$ express myapp
$ cd myapp
$ npm install
$ npm start
You will end up with a working directory that looks like this:
├── app.js
├── bin
│ └── www
├── node_modules
│ ├── ...
├── package.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
│ └── style.css
├── routes
│ ├── index.js
│ └── users.js
└── views
├── error.jade
├── index.jade
└── layout.jade
Go ahead and delete the /routes/users.js
file and the following lines from app.js
...
var users = require('./routes/users');
...
app.use('/users', users);
Then create a new routes file named /routes/foo.js
and and require it from your app server.
...
app.use('/foo', require('./routes/foo'));
...
How to GET /foo
Inside /routes/foo.js
, you need to require the router module from ExpressJS, define a route on it, and export it back out.
var express = require('express')
var router = express.Router()
// GET /foo
router.get('/', function (req, res, next) {
res.send('this is the index for foo')
})
module.exports = router
Everytime you change a route, you need to restart your server. Nevigating to localhost:3000/foo should display the message:

How to GET /foo/bar
Create simple nested routes by requiring the child route file from the parent route file.
var express = require('express')
var router = express.Router()
var bar = require('./bar')
// GET /foo
router.get('/', function (req, res, next) {
res.send('this is the index for foo')
});
// GET /foo/bar
router.use('/bar', bar) // tell the router to use bar.js for child routes
module.exports = router
Create a new routes file named /routes/bar.js
and define a root route the same way you did for /routes/foo.js
:
var express = require('express')
var router = express.Router()
// GET /foo/bar
router.get('/', function (req, res, next) {
res.send('this is the index for bar')
});
module.exports = router
Bounce your server again and navigate to localhost:3000/foo/bar

How to GET /foo/42
Expecting a parameter? No problem! access URL params directly from the request object: req.params.nameOfParam
:
...
// GET /foo/42
router.get('/:number', function (req, res, next) {
res.send('this is foo #' + req.params.number)
})
module.exports = router
Navigate to localhost:3000/foo/42 to see the result.

How to GET /foo/42/baz
Getting a child route from a parameterized parent is where I was getting confused. It turns out that you need to configure the router a little differently when you are passing params through.
...
var baz = require('./baz')
...
// GET /foo/42/baz
router.use('/:number/baz', baz)
module.exports = router
You need to pass an options object to express.Router
to merge the params from any parent route:
var express = require('express')
var router = express.Router({mergeParams: true}) // don't forget the parent params!
// GET /foo/42/baz
router.get('/', function (req, res, next) {
// the param name is from the parent as well
res.send('this is the baz for foo#' + req.params.number);
})
module.exports = router
Navigate to localhost:3000/foo/42/baz to enjoy your success.

How to GET /foo/42/baz/123
Parameterizing a child route is the same process as for the parent route:
var express = require('express')
var router = express.Router({mergeParams: true})
// GET /foo/42/baz
router.get('/', function (req, res, next) {
res.send('this is the baz for foo#' + req.params.number);
})
// GET /foo/42/baz/123
router.get('/:id', function (req, res, next) {
res.send('baz #' + req.params.id + ‘ for foo #’ + req.params.number)
})
module.exports = router
Navigate to localhost:3000/foo/42/baz/123 to enjoy your success.

TADA! a model of nested routes that you can apply to any application.