File-Based Routing in Node.js

dsitdikov

Daniil Sitdikov

Posted on August 31, 2023

File-Based Routing in Node.js

About a year ago, I tried Next.js for the first time and was so impressed by their file-based routing that I decided to implement a similar system on the backend. I couldn't find anything suitable, so I took it upon myself to create my own solution. It turned out to be technology-agnostic and works with both pure Node.js, Bun and the popular Express.js.

In this brief guide, we will attempt to partially implement a shop's API. This tutorial uses JavaScript and CommonJS module types to keep things simple and quick to get started.

1. Installation

šŸ’æ Install node-file-router:

npm install node-file-router
Enter fullscreen mode Exit fullscreen mode

2. Initialization

Create an server.js file and do the following

If you use pure Node.js:

// 1. Import default http module and node-file-router
const http = require('node:http');
const { initFileRouter } = require('node-file-router');

// 2. Create an entry-point function
async function run() {
  // 3. Initialize node-file-router and the handler function
  const useFileRouter = await initFileRouter();

  const server = http.createServer((req, res) => {
    // 4. Create a server and invoke created function on each request
    useFileRouter(req, res);
  });

  // 5. Start listening a server on 4000 port
  const port = 4000;
  server.listen(port, () =>
    console.log(`Server running at http://localhost:${port}/`)
  );
}

// 6. Run entry-point function
run();
Enter fullscreen mode Exit fullscreen mode

If you use Express.js:

const { initFileRouter } = require('node-file-router');
const express = require('express');

async function run() {
  const fileRouter = await initFileRouter();

  const app = express();

  app.listen(4004);
  app.use(fileRouter);
}

run();
Enter fullscreen mode Exit fullscreen mode

2. A first route

šŸ” We will create a home route that displays welcome content.

1. Create an api folder at the root of your project.

ā”œā”€ā”€ api/ <-
ā”œā”€ā”€ server.js
ā””ā”€ā”€ package.json
Enter fullscreen mode Exit fullscreen mode

2. Create a file named index.js inside this folder:

ā”œā”€ā”€ api/
ā”‚  ā””ā”€ā”€ index.js <-
ā”œā”€ā”€ server.js
ā””ā”€ā”€ package.json
Enter fullscreen mode Exit fullscreen mode
module.exports = function index(req, res) {
  res.end("Welcome to our shop!");
}
Enter fullscreen mode Exit fullscreen mode

3. Run a server using: node server.js command
4. Open a browser and navigate to http://localhost:4000.

You should see the message Welcome to our shop! displayed.

Congratulations! šŸŽ‰ You've created a first file route

3. Add http methods

1. Before we start, we need a small utility function which will parse json from a request.
Create a folder utils and put http.utils.js file inside.

ā”œā”€ā”€ api/
ā”œā”€ā”€ ...
ā”œā”€ā”€ utils/
ā”‚  ā””ā”€ā”€ http.utils.js <-
...
Enter fullscreen mode Exit fullscreen mode
module.exports = {
  parseJson(request) {
    return new Promise((resolve, reject) => {
      let data = '';

      request.on('data', (chunk) => {
        data += chunk;
      });

      request.on('end', () => {
        try {
          const parsedData = JSON.parse(data);
          resolve(parsedData);
        } catch (e) {
          reject(e);
        }
      });
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Create a folder called products and an index.js file inside it.

ā”œā”€ā”€ api/
ā”‚  ā”œā”€ā”€ products/ <-
ā”‚  ā”‚  ā””ā”€ā”€ index.js <-
ā”‚  ā””ā”€ā”€ ...
...
Enter fullscreen mode Exit fullscreen mode

3. Implement get and post methods:

const { parseJson } = require('../../utils/http.utils');

module.exports = {
  get: (req, res) => {
    res.end('list of products');
  },
  post: async (req, res) => {
    const newProduct = await parseJson(req);
    res.end(`a product will be created: ${JSON.stringify(newProduct)}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Open a browser and go to http://localhost:4000/products.

You should see a list of products message displayed.

4. Make a POST request using curl, Postman or any tool you like on http://localhost:4000/products

The response should display a product will be created along with your content.

Perfect! šŸŽ‰ Let's move on

4. Dynamic routes

1. Create a new file with the name [id] inside the product folder.

ā”œā”€ā”€ api/
ā”‚  ā”œā”€ā”€ products/
ā”‚  ā”‚  ā”œā”€ā”€ ...
ā”‚  ā”‚  ā””ā”€ā”€ [id].js <-
ā”‚  ā””ā”€ā”€ index.js
...
Enter fullscreen mode Exit fullscreen mode

2. Fill it the same way as you did before:

module.exports = {
  // Add the `routeParams` argument as the final argument to the function. This argument will contain
  // all the taken route parameters.
  get: (req, res, routeParams) => {
    const { id } = routeParams;
    res.end(`product ${id} info`);
  }
};
Enter fullscreen mode Exit fullscreen mode

3. Open a browser and go to http://localhost:4000/products/123.

The page should display a message: product 123.

Alright, let's make it more sophisticated.

Say, we want to address the following case:
/catalog/tag-1/tag-2/tag-n

4. Create a catalog folder with [[...categories]].js inside.

ā”œā”€ā”€ api/
ā”‚  ā”œā”€ā”€ catalog/
ā”‚  ā”‚  ā”œā”€ā”€ ...
ā”‚  ā”‚  ā””ā”€ā”€ [[...categories]].js <-
ā”‚  ā”œā”€ā”€ index.js
...
Enter fullscreen mode Exit fullscreen mode

And add a single get method:

module.exports = {
  get: (req, res, routeParams) => {
    const { categories } = routeParams;

    // This type of route also covers just "/catalog"
    if (!categories) {
      return res.end('all products');
    }

    res.end(`get products that have such tags: ${categories}`);
  },
};
Enter fullscreen mode Exit fullscreen mode

5. Open a browser and go to http://localhost:4000/catalog/men/sneakers/nike.

The page should display a list of categories: men, sneakers, nike

šŸ„ That's it!

What's next?

  1. Discover more capabilities of the routing system
  2. Configuration and More Details
  3. Examples with Express, WebSockets, ECMAScript, and more
  4. How to create your own custom adapter and use it with your favourite framework
  5. Usage with Bun
šŸ’– šŸ’Ŗ šŸ™… šŸš©
dsitdikov
Daniil Sitdikov

Posted on August 31, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

File-Based Routing in Node.js
javascript File-Based Routing in Node.js

August 31, 2023