How to Write Smarter Routing With Express and Node.js
By: Rogerio Amorim
Tags: JavaScript, Nodejs, Expressjs, Programming, Node

How to Write Smarter Routing With Express and Node.js

Let the Node file system do the heavy lifting

Photo by You X Ventures on Unsplash

Express is a web application framework for Node. It provides various features that make web-application development fast and easy, a task that otherwise takes more time when using only Node.

There are many ways you can create and manage routes using Express, the most simple and direct being through the use of the delete , get , post , and put methods. Each one of them is mapped to the equivalent request HTTP verb.

In the example above, we have three routes ( / , /home , /about ), each one with two different HTTP verbs ( get , post ) and its own logic that’s sending a unique text to the client

As you can see from this tiny example, this kind of approach can get very messy when the number of routes increase.

There’s a way we can make this code better by using the route method and method chaining to equal paths:

This way we can make the code a little bit shorter, but it’s still messy since we have multiple route paths in the same file.

Our next step is to create a separate file for each path and make use of the Express Router object. The Router object is an isolated instance of middleware and routes. You can think of it as a mini-application, capable only of performing middleware and routing functions.

This way, we have cleaner code in the main file, index.js , and each route is defined in its own file. In addition to the Route object, we make use of the Express method use to map the path to its configuration file.

It’s much better than what we had in the earlier examples, but I can still see some problems here — like the code repetition in each route file and, mainly, the fact that every time we add new route files to the app, we need to change the main file to map the path to the file. When we have a great number of routes, we have the same problem: The main file code gets bigger and messy.

To solve the second issue, we can make a separate file to map each path to its route file and do a simple require in the main file.

The routes folder index file receives the app instance from the main file and makes the path mapping. The main file makes use of the Immediately Invoked Function Expression to require and execute the routes index file passing the app created. Now we have a cleaner main file, but we still have the problem that it’s required to manually map each path to its file.

Node can help us make this better if we can make it loop through the routes folder’s files and make the mapping. To achieve this, we’ll make use of Node’s fs.readdirSync . This method is used to synchronously read the contents of a given directory. The method returns an array with all the file names or objects in the directory.

And you may ask, what about the path? If we don’t have an automated way to discover the path of each route file, we’ll still have to edit the list for each route added. I can see two kinds of solutions for this issue: to use convention over configuration or to add a export with the path in the route file.

To use convention over configuration, we’ll use the filename as the route path. To make it safer and to remove potential problematic characters, we’ll use Lodash to convert the filename to snakeCase, where strings are separated by an underscore.

Another change we’ll make is to use the Router object only in the routes config file, making the route code simpler and avoiding code repetition.

Besides this, we’ll make use the path.join Node method to make our code cross-platform, since Windows and Linux-based systems use different path names:

The other option, as I said earlier, is to export the desired path name in the route file and use this information in the route config file.

To achieve this, we’ll have to export an object with the path and config keys in our route file. In this kind of configuration, I strongly suggest you use the filename path method as a fallback to avoid errors in case you forget to add the path export. This way, we have an extra bonus: a solution that’ll work on both situations.

In our final example, we’ll change the home route path to my_home and leave the about route file as it was.

And that’s it. Here we have our smarter Express router config. By using this kind of configuration — and solutions like PM2 or Nodemon to watch your app folder and restart automatically on file changes — all you have to do to add a new route is to add a file in the routes folder.

Of course, there’s plenty of space for improvements, like error checking, but this kind of feature I’ll leave to you so you can get used to the code provided and practice your coding skills while trying to achieve whichever feature you think isn’t implemented in my example. To make things easier in your journey, I’ve provided the final code in CodeSandbox. Feel free to fork and work on it.

I hope you’ve learned something useful in this article. See you next time!