Node.js, Module.Exports and Organizing Express.js Routes

A while ago I wrote a post explaining how require and module.exports work. Today I wanted to show a practical example of how we can use that knowledge to organize routes in an express.js project.

To recap the original post, module.exports is how we make something within our file publicly accessible to anything outside our file. We can export anything: a class, a hash, a function or a variable. When you require something you get whatever it exported. That means that the return value from require can be a class, a hash, a function or a variable. The end result is that how the value returned from require is used can vary quite a bit:

With that in mind, I happen to be building a website that'll have two distinct sections: an API and a user-facing portal. I'd like to organize my routes/controllers as cleanly as possible. The structure that I'd like is:

This is very Rails-esque with controller namespaces and resources. Ideally, I'd like controllers under API (stats and scores) to have access to common API-based methods. How can we cleanly achieve this?

Before we can dive any further we need to understand how express loads routes. You basically attach the route to the express object. The simplest example might look something like:

The syntax might be strange, but there's nothing new here. First, our exports isn't doing anything other than exporting a function that takes a single parameter. Secondly, our require is loading that function and executing it. We could have rewritten the relevant parts more verbosely as:

So how do we take this to the next level? Well, we don't want to have to import a bunch of different routes at the base level. We want to use require('./routes')(app) and let that load all the necessary routes. So, the first thing we'll do is put an index file in a routes folder:

When you tell node.js to require a folder, it automatically loads its index file. With the above, our initial route loading remains untouched: require('./routes')(app). Now, this loading code doesn't just include routes/index.coffe it actually executes it (it's calling the function and passing in the app as an argument). All our routes function does is load and execute more functions.

For both our API and portal, we can do the same thing we did for routes:

This is a good solution to help us organize our code, but what about sharing behavior? For example, many API functions will want to make sure requests are authenticate (say, using an SHA1 hash of the parameters and signature).

Our first attempt will be to add some utility methods to the api/index.coffee file:

For those who don't know, when an express route is given 3 parameters, the 2nd one is treated as something of a before-filter (you can pass in an array of them and they'll be processed in order).

This solution is pretty good, but we can take it a step further and create some inheritance. The main benefit is not having to specify api. all over the place. So, we change our api/index.coffee one last time:

And that, is that. There's a lot going on in all of this, but the key takeaway is that you can export anything and that flexibility can lead to some fairly well organized code. You can also leverage the fact that the index file is automatically loaded when its folder is required to keep things nice and clean.

I know this jumped all over the place, but hopefully you'll find it helpful!