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
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();
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();
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 which will parse json from a request.
Create a folder utils
and put http.utils.js
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.
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!
Top comments (3)
It's amazing to see how you were inspired by Next.js' file-based routing and took it upon yourself to create a technology-agnostic solution for the backend, compatible with both Node.js and Express.js. This tutorial is a valuable resource for anyone looking to implement a shop's API. Good job!
Wow, thank you so much!! No more complicated βifsβ and RegExps. I got used to the router in Next.js, too and iβm happy that i can do the same on the backend
Great, but how do I also serve static files like images?