Organizing your application structure and its routes is one of the first problems you will encounter while developing with Express. To help you with that version 4 added the Router class.
Let’s use it to define some routes in a cars.js file.
var
express
require
'express'
router
express
Router
// Car brands page
router
get
'/brands'
function
req
res
res
send
'Audi, BMW, Mercedes'
// Car models page
router
get
'/models'
function
req
res
res
send
'Audi Q7, BMW X5, Mercedes GL'
module
exports
router
We define the brands and the models routes and then we export the entire router, so that we can use it elsewhere. This makes defining controllers in an MVC style app much more modular. This will later help us when we build larger more complex applications.
Let’s load our new routes in an Express app.
var
express
require
'express'
app
express
app
use
'/cars'
require
'./cars'
app
listen
3000
function
console
log
'Listening on port 3000...'
This app will respond to /cars/brands or /cars/models requests, with the data we defined above.
The most important bit, from the app file above, is
app
use
'/cars'
require
'./cars'
It loads the router with its routes and defines a prefix for all the routes loaded inside. The prefix part is optional. You could write for example
app
use
require
'./cars'
Then the server will respond only to requests from /brands and /models.
Using the routers for structuring your app
Let’s use those features in a bigger MVC app with the following file structure:
controllers/
animals.js
cars.js
index.js
models/
public/
tests/
app.js
package.json
cars.js will be the same as above and animals.js will define a few more routes.
var
express
require
'express'
router
express
Router
// Domestic animals page
router
get
'/domestic'
function
req
res
res
send
'Cow, Horse, Sheep'
// Wild animals page
router
get
'/wild'
function
req
res
res
send
'Wolf, Fox, Eagle'
module
exports
router
Again, we define the routes and then the router is exported, nothing new. Our next file controllers/index.js will be responsible for loading all controllers, which we’ve already implemented. It will also define some more routes but without prefix, like a home page and an about page.
var
express
require
'express'
router
express
Router
router
use
'/animals'
require
'./animals'
router
use
'/cars'
require
'./cars'
router
get
'/'
function
req
res
res
send
'Home page'
router
get
'/about'
function
req
res
res
send
'Learn about us'
module
exports
router
Every router can load other routers. This is very handy when you are organizing your app. You can build a hierarchy of routers and routes, if you really need it. I prefer to keep it only one level deep as in the example above. There, we first include our existing routers with their routes and then we define two more routes, before as usual to return the current router which contain all routes.
To load them, you only need to load the controllers/index.js file. Moreover, it is an index file, so you don’t need to provide its name when requiring it, you only need the folder name.
var
express
require
'express'
app
express
app
use
require
'./controllers'
app
listen
3000
function
console
log
'Listening on port 3000...'
This is all you need to begin serving all routes defined in all your controllers. Your app will be responding to requests to the following paths.
- /
- /about
- /animals/domestic
- /animals/wild
- /cars/brands
- /cars/models
Notice how easy is to organize your routes with the new Router class. Thanks to it the dependency is only in one direction. Routers don’t know where they are used, they only know the routers they themselves include. This greatly simplifies dependencies.
Router specific middlewares
Middlewares in express are extremely useful. They can load sessions, extract useful data, put common headers and much more. While most of the time we add middlewares for the entire app with app.use, sometimes it is also useful to have them only for some routes. In such cases you would usually add the middleware to every individual path definition.
var
express
require
'express'
router
express
Router
// Middleware
function
authorize
req
res
next
req
user
===
'farmer'
next
else
res
status
403
send
'Forbidden'
// Domestic animals page
router
get
'/domestic'
authorize
function
req
res
res
send
'Cow, Horse, Sheep'
// Wild animals page
router
get
'/wild'
authorize
function
req
res
res
send
'Wolf, Fox, Eagle'
module
exports
router
In larger more complex apps, having to add the middleware to each individual route quickly becomes tedious. In such cases you can add the middleware directly to the router.
var
express
require
'express'
router
express
Router
// Applying middleware to all routes in the router
router
use
function
req
res
next
req
user
===
'farmer'
next
else
res
status
403
send
'Forbidden'
// Domestic animals page
router
get
'/domestic'
function
req
res
res
send
'Cow, Horse, Sheep'
// Wild animals page
router
get
'/wild'
function
req
res
res
send
'Wolf, Fox, Eagle'
module
exports
router
The middlware will be executed only for all routes defined in this router and only for them. This can be used for defining whole controller authorization or making some input data transformation which will be then used everywhere inside the router or another common task.
Other benefits
The benefits of using routers will be felt on the all parts of your project. Separating the controllers with their own routers makes them more modular and easier to test. You can also move around your controller both inside your file structure and in your path hierarchy, without affecting your code. All of this makes maintaining your application and working with larger team easier.
What’s next
If you are starting a new project you can clone the base-express repository from GitHub and use it as your starting point. It is already using the patterns shown above and it has a few more handy stuff. It is also always up to date with the latest version of Express and the latest versions of a few other libraries.
If you already have an existing app and you would like to use the Router class, I strongly recommend to first update to the latest express. Then rewrite the parts of your code that need rewriting. It will be easier and faster than you think. It will also result in much cleaner code and structure which is also easier to test and maintain.