How to write a scalable router for express in nodejs.
Tags: node, javascript, mern
Published: 2020-09-06 07:19:28

I have been looking for a good way to handling routing in MERN project, scalable and robust router, there were many articles but somewhat confusing for beginners so I decided to simplify it for and what else could be a good topic for the first article at dev.to.

Here we will assume we are working on a large project that provides API to front-end with a bunch of routes. 

## let's dive in

### 1. Create a folder in root directory 
I prefer it naming routes, ofcourse you can name anything you like
``` ~/routes ```

### 2. Create root router
Now, that we have a folder to hold all of our routes, we can have the root router in it. Create a ` router.js ` file in the ` ~/routes ` folder.

### 3. Create and export the router

``` 
const express = require("express"); 
const router = express.Router();
const subRouters = []; //will get subRouters soon
router.use(subRouters);
module.exports = router;

```
Now you can import this router in your main file and let express use it.

### 4. Creating sub routers
 In the ` ~/routes` folder create more folders according to your need; for demo I will create a couple of folders

`~/routes/auth
~/routes/profile
~/routes/chat `

create routers in subfolders accordingly, for example, `~routes/auth` could have `login.js` and `register.js`.
Here `~/routes/auth/register.js` 

```
const express = require("express"); 
const router = express.Router();


router.post(
  "/api/users",
  async (req, res) => {

 //your logic here 
}
module.exports = router;
```
### 5. The Fun part- telling your root router to look for subRouters

Now that we have a couple of routers in subfolders -there can be as many as you want- we tell our root router to import them. Importing them manually one by one could be tedious also if we add any subRouter in the future we would have to come back to root router again and take care of it manually. 

Import file system and path module we will use them to look take a look in the directory.
```
const fs = require("fs");
const path = require("path");
``` 
Now let's get subroutes, we are defining here an empty array to hold all imported subRoutes and a function `getAllSubroutes` given a directory to this it will look for all files in the directory and import them in subRoutes array, 
  
```
const subRouters = [];
const getAllSubroutes = (dir) => {
  fs.readdirSync(dir).forEach((file) => {
    const fullPath = path.join(dir, file);
    if (fs.lstatSync(fullPath).isDirectory()) {
      getAllSubroutes(fullPath);
    } else {
      if (fullPath !== __filename) {
        subRouters.push(require(fullPath));
      }
    }
    return subRouters;
  });
};
```
if it come across a directory it will search it recursively - take note 
``` if (fs.lstatSync(fullPath).isDirectory()) {
          getAllSubrouts(fullPath); ```
incase you are wondering `forEach` is builtin array function works similar to for loop. Also , notice in else block we check `if (fullPath !== __filename) ` this ensure we do, not import rootRouter into itslef .

### 6. Call `getAllSubroutes` 
Next, we put our function to work, call it with argument of `__dirname`; this is global property available in every file pointing to its directory.
now your ` ~routes/rootRouer/router.js ` should look like this.
```
//root router

const express = require("express");
const fs = require("fs");
const path = require("path");

const router = express.Router();

const subRouters = [];
const getAllSubroutes = (dir) => {
  fs.readdirSync(dir).forEach((file) => {
    const fullPath = path.join(dir, file);
    if (fs.lstatSync(fullPath).isDirectory()) {
      getAllSubroutes(fullPath);
    } else {
      if (fullPath !== __filename) {
        subRouters.push(require(fullPath));
      }
    }
    return subRouters;
  });
};

 getAllSubroutes(__dirname)
router.use(subRouters);

module.exports = router;
```
Now, we can add or remove as many routes according to our needs, without requiring us to change anything else.
This is off-course one of the preferred ways, let me know in the comments what do you think about this method?
Thanks for reading!😊