Creating Routes
Organize your API into modular route files using Express Router — keep your code clean and maintainable as the API grows.
Creating Routes
As your API grows, putting all routes in a single file becomes unmanageable. Express provides the Router class that lets you group related routes into separate files. In this episode you will organize your API into modular, maintainable route files.
The Problem: Everything in One File
// index.js — this gets messy fast!
app.get('/api/ninjas', ...);
app.post('/api/ninjas', ...);
app.get('/api/ninjas/:id', ...);
app.put('/api/ninjas/:id', ...);
app.delete('/api/ninjas/:id', ...);
app.get('/api/weapons', ...);
app.post('/api/weapons', ...);
// ... dozens more routes
Express Router
The express.Router() creates a mini Express application that can have its own routes and middleware. You define routes in separate files and mount them on the main app.
Step 1: Create the Routes Folder
rest-api/
├── routes/
│ └── ninjas.js (ninja routes)
├── index.js
└── package.json
Step 2: Define Routes in a Router File
routes/ninjas.js
const express = require('express');
const router = express.Router();
// GET all ninjas
router.get('/', (req, res) => {
res.json({ message: 'GET all ninjas' });
});
// GET a single ninja
router.get('/:id', (req, res) => {
res.json({ message: 'GET ninja ' + req.params.id });
});
// POST a new ninja
router.post('/', (req, res) => {
res.json({ message: 'POST a new ninja', data: req.body });
});
// PUT (update) a ninja
router.put('/:id', (req, res) => {
res.json({ message: 'PUT ninja ' + req.params.id });
});
// DELETE a ninja
router.delete('/:id', (req, res) => {
res.json({ message: 'DELETE ninja ' + req.params.id });
});
module.exports = router;
Notice that routes use / and /:id instead of /api/ninjas and /api/ninjas/:id. The prefix is defined when the router is mounted.
Step 3: Mount the Router in index.js
const express = require('express');
const ninjaRoutes = require('./routes/ninjas');
const app = express();
app.use(express.json());
// Mount the ninja routes at /api/ninjas
app.use('/api/ninjas', ninjaRoutes);
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
The app.use('/api/ninjas', ninjaRoutes) line mounts the router at /api/ninjas. All routes defined in the router are prefixed with this path:
| Router Route | Mounted Path | Full URL |
|---|---|---|
router.get('/') | /api/ninjas | GET /api/ninjas |
router.get('/:id') | /api/ninjas | GET /api/ninjas/123 |
router.post('/') | /api/ninjas | POST /api/ninjas |
router.delete('/:id') | /api/ninjas | DELETE /api/ninjas/123 |
Adding More Route Files
// routes/weapons.js
const router = express.Router();
router.get('/', (req, res) => { ... });
module.exports = router;
// index.js
const weaponRoutes = require('./routes/weapons');
app.use('/api/weapons', weaponRoutes);
Each resource gets its own route file. The main index.js stays clean — it only imports and mounts routers.
Route Files with Method Chaining
router.route('/')
.get((req, res) => {
res.json({ message: 'GET all ninjas' });
})
.post((req, res) => {
res.json({ message: 'POST a new ninja' });
});
router.route('/:id')
.get((req, res) => {
res.json({ message: 'GET ninja ' + req.params.id });
})
.put((req, res) => {
res.json({ message: 'PUT ninja ' + req.params.id });
})
.delete((req, res) => {
res.json({ message: 'DELETE ninja ' + req.params.id });
});
router.route() lets you chain multiple methods on the same path — reducing repetition and grouping related handlers together.
Key Takeaways
express.Router()creates a modular, mountable set of routes- Define routes in separate files under a
routes/folder for clean organization - Mount routers with
app.use('/prefix', router)— the prefix is prepended to all router routes - Routes inside the router use relative paths (
/,/:id) — the prefix is added byapp.use() router.route()chains multiple HTTP methods on the same path