paint-brush
File-Based Routing in Node.js: A Brief Guideโ€‚by@dsitdikov
2,666 reads
2,666 reads

File-Based Routing in Node.js: A Brief Guide

by Daniil SitdikovSeptember 1st, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

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 backend
featured image - File-Based Routing in Node.js: A Brief Guide
Daniil Sitdikov HackerNoon profile picture

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 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

2. Initialization

Create a 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();

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(4000);
  app.use(fileRouter);
}

run();

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

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

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

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 that will parse JSON from a request. Create a folder utils and put http.utils.js the file inside.

โ”œโ”€โ”€ api/
โ”œโ”€โ”€ ...
โ”œโ”€โ”€ utils/
โ”‚  โ””โ”€โ”€ http.utils.js <-
...
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);
        }
      });
    });
  }
}

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

โ”œโ”€โ”€ api/
โ”‚  โ”œโ”€โ”€ products/ <-
โ”‚  โ”‚  โ””โ”€โ”€ index.js <-
โ”‚  โ””โ”€โ”€ ...
...

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)}`);
  }
}

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
...


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`);
  }
};

3. Open a browser and go to http://localhost:4000/products/123. <br/> 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
...

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}`);
  },
};

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 favorite framework