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?