Skip to main content

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:

javascript
// 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:

javascript
// 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:

javascript
// 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:

javascript
// 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;
javascript
// 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;
javascript
// 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:

javascript
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:

javascript
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:

javascript
// 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;
javascript
// 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;
javascript
// 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​

  1. Organize Routes by Resource: Create separate router files for each major resource in your application (users, products, etc.).

  2. Use Descriptive Names: Name your router files in a way that clearly indicates what resources they handle.

  3. Keep Routers Focused: Each router should focus on a specific set of related routes.

  4. Use Router Parameters: Take advantage of the router.param() middleware to handle common operations for specific parameters.

  5. Apply Router-Level Middleware: Use router-specific middleware for authentication, logging, or other operations that apply to a specific set of routes.

  6. 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​

  1. Create a simple Express application with separate routers for handling blog posts and authors.

  2. Implement a router that requires authentication (using a simple middleware function) for all its routes.

  3. Build a nested router structure for an e-commerce API with products, categories, and reviews.

  4. Enhance the blog example by adding a router for handling user authentication (register, login, logout).

  5. 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 feedback@compilenrun.com. I’d greatly appreciate your feedback! :)