Express Router Object
Introduction
When building web applications with Express.js, you'll often need to handle multiple routes with different HTTP methods. As your application grows, managing all routes in a single file can become unwieldy and difficult to maintain. This is where the Express Router object comes in handy.
The Express Router is a complete middleware and routing system that allows you to create modular, mountable route handlers. Think of it as a "mini-app" that can handle routes independently and then be mounted to your main Express application. This promotes better organization, code reusability, and maintainability of your application.
Understanding the Express Router
What is the Router?
The Router object is an isolated instance of middleware and routes. It can be thought of as a "mini-application" capable only of performing middleware and routing functions. Every Express application has a built-in app router.
Basic Router Creation
Here's how you can create a router object:
// Import Express
const express = require('express');
// Create a router instance
const router = express.Router();
Setting Up Routes with the Router
Let's see how we can define routes using the Router object:
// Import Express
const express = require('express');
// Create a router instance
const router = express.Router();
// Define routes
router.get('/', (req, res) => {
res.send('Home page');
});
router.get('/about', (req, res) => {
res.send('About page');
});
// Export the router
module.exports = router;
Mounting the Router in Your App
After creating and configuring your router, you need to mount it to your Express application:
// app.js
const express = require('express');
const app = express();
const routes = require('./routes'); // Import the router module
// Mount the router on the app
app.use('/', routes);
// Start the server
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
Creating Multiple Routers for Different Resource Types
One of the biggest advantages of using the Router is creating separate route handlers for different resources in your application. Let's look at an example with users and products:
// userRoutes.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.send('Get all users');
});
router.post('/', (req, res) => {
res.send('Create a new user');
});
router.get('/:id', (req, res) => {
res.send(`Get user with ID: ${req.params.id}`);
});
module.exports = router;
// productRoutes.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.send('Get all products');
});
router.post('/', (req, res) => {
res.send('Create a new product');
});
router.get('/:id', (req, res) => {
res.send(`Get product with ID: ${req.params.id}`);
});
module.exports = router;
// app.js
const express = require('express');
const app = express();
const userRoutes = require('./userRoutes');
const productRoutes = require('./productRoutes');
// Mount routers with path prefixes
app.use('/users', userRoutes);
app.use('/products', productRoutes);
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
With this structure, requests to /users
will be handled by the user router and requests to /products
will be handled by the product router.
Router Parameters
The Router object allows you to define parameters in your routes, similar to the main Express application:
const express = require('express');
const router = express.Router();
// Parameter middleware
router.param('userId', (req, res, next, userId) => {
// Perform operations on userId
console.log(`User ID: ${userId}`);
// You could fetch the user from a database
req.user = { id: userId, name: 'John Doe' };
next(); // Continue to the route handler
});
// Route that uses the parameter
router.get('/users/:userId', (req, res) => {
res.send(`User: ${req.user.name}`);
});
module.exports = router;
Router-Level Middleware
You can add middleware functions that are specific to a router. This is useful for operations that should happen for all routes in that router:
const express = require('express');
const router = express.Router();
// Router-level middleware
router.use((req, res, next) => {
console.log('Time:', Date.now());
next();
});
// Authentication middleware for specific routes
const authenticate = (req, res, next) => {
// Check if user is authenticated
if (req.query.authToken === 'secret') {
next(); // User is authenticated, proceed to the route handler
} else {
res.status(401).send('Unauthorized');
}
};
// Public route
router.get('/public', (req, res) => {
res.send('This is a public route');
});
// Protected route using the middleware
router.get('/protected', authenticate, (req, res) => {
res.send('This is a protected route');
});
module.exports = router;
Real-World Example: Blog API
Let's see a more complete example of how to use the Express Router in a blog application with posts and comments:
// postRoutes.js
const express = require('express');
const router = express.Router();
// Sample data (in a real app, this would be a database)
const posts = [
{ id: 1, title: 'First Post', content: 'Hello world!' },
{ id: 2, title: 'Express Router', content: 'Routers are awesome!' }
];
// Get all posts
router.get('/', (req, res) => {
res.json(posts);
});
// Get a single post by id
router.get('/:id', (req, res) => {
const post = posts.find(p => p.id === parseInt(req.params.id));
if (!post) return res.status(404).send('Post not found');
res.json(post);
});
// Create a new post
router.post('/', (req, res) => {
const post = {
id: posts.length + 1,
title: req.body.title,
content: req.body.content
};
posts.push(post);
res.status(201).json(post);
});
module.exports = router;
// commentRoutes.js
const express = require('express');
const router = express.Router({ mergeParams: true }); // mergeParams allows access to parent router params
// Sample data
const comments = {
1: [
{ id: 1, text: 'Great post!' },
{ id: 2, text: 'Thanks for sharing' }
],
2: [
{ id: 1, text: 'Routers are indeed useful' }
]
};
// Get all comments for a post
router.get('/', (req, res) => {
const postId = parseInt(req.params.postId);
const postComments = comments[postId] || [];
res.json(postComments);
});
// Add a comment to a post
router.post('/', (req, res) => {
const postId = parseInt(req.params.postId);
if (!comments[postId]) {
comments[postId] = [];
}
const comment = {
id: comments[postId].length + 1,
text: req.body.text
};
comments[postId].push(comment);
res.status(201).json(comment);
});
module.exports = router;
// app.js
const express = require('express');
const app = express();
const postRoutes = require('./postRoutes');
const commentRoutes = require('./commentRoutes');
app.use(express.json()); // Middleware to parse JSON bodies
// Mount the post router
app.use('/api/posts', postRoutes);
// Mount the comment router under posts
// This allows routes like /api/posts/:postId/comments
app.use('/api/posts/:postId/comments', commentRoutes);
app.listen(3000, () => {
console.log('Blog API server is running on port 3000');
});
This example demonstrates a common pattern in REST APIs where resources like comments are nested under parent resources (posts in this case).
Best Practices for Using Express Router
-
Organize Routes by Resource: Create separate router files for each major resource in your application (users, products, etc.).
-
Use Descriptive Names: Name your router files in a way that clearly indicates what resources they handle.
-
Keep Routers Focused: Each router should focus on a specific set of related routes.
-
Use Router Parameters: Take advantage of the
router.param()
middleware to handle common operations for specific parameters. -
Apply Router-Level Middleware: Use router-specific middleware for authentication, logging, or other operations that apply to a specific set of routes.
-
Use Proper HTTP Methods: Stick to RESTful conventions by using the appropriate HTTP methods (GET for retrieving, POST for creating, PUT for updating, DELETE for removing).
Summary
The Express Router object is a powerful tool for organizing routes in your Express.js applications. It helps you:
- Create modular, mountable route handlers
- Organize routes by resource type
- Apply middleware to specific groups of routes
- Build cleaner and more maintainable applications
By separating your routes into logical modules, your application becomes easier to understand, test, and maintain, especially as it grows in complexity.
Additional Resources
Exercises
-
Create a simple Express application with separate routers for handling blog posts and authors.
-
Implement a router that requires authentication (using a simple middleware function) for all its routes.
-
Build a nested router structure for an e-commerce API with products, categories, and reviews.
-
Enhance the blog example by adding a router for handling user authentication (register, login, logout).
-
Create a router that serves static files from different directories based on the route prefix.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)