Building Scalable Express.js APIs: The Power of Modular Routing
When building a larger Express.js application, handling all your routes in a single file quickly becomes unmanageable. Instead, using modular routing can help keep your code clean, scalable, and easier to maintain. In this article, weβll walk through setting up a modular route structure for your Express.js app.
Why Modular Routing?
As your application grows, so does the number of routes. Keeping everything in a single server.ts
file leads to poor maintainability and harder debugging. By breaking routes into separate files, we achieve:
β
Better Organization β Routes are logically grouped into folders.
β
Scalability β New features and API versions are easier to add.
β
Improved Readability β Developers can quickly find and manage specific routes.
Setting Up API Versioning
A good practice in REST API development is to introduce versioning. This allows users to transition between API versions without breaking their implementations. Weβll namespace our API under /v1
so that future versions (/v2
, /v3
, etc.) can be developed without affecting the older versions.
Step 1: Creating the Route Structure
Instead of keeping everything in server.ts
, weβll create a routes folder with a modular structure:
π src/routes/v1
π tasks/
(Handles task-related routes)
π projects/
(Handles project-related routes)
π index.ts
(Main router for version 1 API)
First, create a new file src/routes/v1/index.ts
and define the main router:
import express from "express";
import tasks from "./tasks";
import projects from "./projects";
const v1 = express.Router();
v1.use("/tasks", tasks);
v1.use("/projects", projects);
export default v1;
This file acts as the entry point for all routes under /v1
, delegating requests to their respective modules.
Step 2: Defining Task Routes
Next, create the tasks
router in src/routes/v1/tasks/index.ts
:
import express from "express";
import { listTasks, getTask } from "./controller";
const tasks = express.Router();
tasks.get("/", listTasks);
tasks.get("/:id", getTask);
export default tasks;
Then, define the task controllers in src/routes/v1/tasks/controller.ts
:
import { Request, Response } from "express";
export const listTasks = (req: Request, res: Response) => {
res.status(200).json([]);
};
export const getTask = (req: Request, res: Response) => {
res.status(200).json({ id: 1, name: "Task 1" });
};
πBoost your career with π IBM Full Stack Software Developer Certificate
Step 3: Defining Project Routes
Now, define the projects
router in src/routes/v1/projects/index.ts
:
import express from "express";
import { listProjects, getProject, listProjectTasks } from "./controller";
const projects = express.Router();
projects.get("/", listProjects);
projects.get("/:id", getProject);
projects.get("/:id/tasks", listProjectTasks);
export default projects;
Then, create the project controllers in src/routes/v1/projects/controller.ts
:
import { Request, Response } from "express";
export const listProjects = (req: Request, res: Response) => {
res.status(200).json([]);
};
export const getProject = (req: Request, res: Response) => {
res.status(200).json({ id: 1, name: "Project 1" });
};
export const listProjectTasks = (req: Request, res: Response) => {
res.status(200).json([]);
};
Step 4: Connecting Routes in server.ts
Now, import and use the modular routes in server.ts
:
import express from "express";
import v1 from "./routes/v1";
const app = express();
app.use("/v1", v1);
app.listen(3001, () => {
console.log("Server running on port 3001");
});
This ensures that all routes under /v1
are correctly registered.
Step 5: Testing the Routes
Start your server with:
npm run dev
Then, test your API using Postman or an HTTP client:
Endpoint | Method | Response |
---|---|---|
/v1/tasks | GET | [] (empty array) |
/v1/tasks/1 | GET | { id: 1, name: "Task 1" } |
/v1/projects | GET | [] (empty array) |
/v1/projects/1 | GET | { id: 1, name: "Project 1" } |
/v1/projects/1/tasks | GET | [] (empty array) |
Conclusion
Thatβs a wrap on Express.js modular routing! By structuring routes properly, we:
β Kept code clean and organized
β Made it easier to scale the app
β Separated concerns for better maintainability
Now you can apply modular routing to your Express.js projects and build scalable APIs with ease!