HVRDHVRD
ExpressJS

Router

Comprehensive guide to using Express Router for modular route handling in Node.js applications, including detailed examples, route parameters, middleware usage, and best practices.

Express Router: Organizing Your Routes

In Express.js, the Router is a built-in mechanism that helps you organize your application’s route handling by creating modular, mountable route handlers.

Without the router, all your routes would live in a monolithic app.js or index.js, which quickly becomes unmanageable as your application grows.


Why Use Express Router?

  • Modularity: Split your application into separate route files based on functionality.
  • Reusability: Reuse route modules across applications.
  • Maintainability: Easier to manage and navigate large codebases.
  • Middleware Isolation: Apply middleware only to specific routes.

Basic Usage Example

Step 1: Create a Simple Express App

const express = require('express');
const app = express();
app.use(express.json());

app.get('/', (req, res) => {
  res.send('Welcome to the main API!');
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Step 2: Using Express Router

Define Routes in a Separate File (userRoutes.js):

const express = require('express');
const router = express.Router();

// Sample users data
const users = [
  { id: 1, name: 'Harsha' },
  { id: 2, name: 'Alex' }
];

// Route: Get all users
router.get('/', (req, res) => {
  res.json(users);
});

// Route: Get user by ID
router.get('/:id', (req, res) => {
  const user = users.find(u => u.id === parseInt(req.params.id));
  if (user) {
    res.json(user);
  } else {
    res.status(404).json({ error: 'User not found' });
  }
});

// Export the router
module.exports = router;

Integrate Router into Main App (app.js):

const express = require('express');
const userRoutes = require('./userRoutes');

const app = express();
app.use(express.json());

// Mount the user routes at /users
app.use('/users', userRoutes);

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Now, visiting /users will return all users, and /users/1 will return the user with id = 1.


Route Parameters and Query Parameters

Route Parameters Example

router.get('/profile/:username', (req, res) => {
  const username = req.params.username;
  res.send(`Profile page of ${username}`);
});

Request: GET /profile/harsha → Response: "Profile page of harsha"


Query Parameters Example

router.get('/search', (req, res) => {
  const query = req.query.q;
  res.send(`Search results for: ${query}`);
});

Request: GET /search?q=express → Response: "Search results for: express"


Applying Middleware to Router

Middleware functions are functions that have access to the request object, response object, and next middleware function in the application’s request-response cycle.

Example: Logging Middleware

const logger = (req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
};

router.use(logger);

This will log every request to the router endpoints.


Advanced Usage: Router-Level Middleware

// Protect routes with authentication middleware
function authMiddleware(req, res, next) {
  const token = req.headers['authorization'];
  if (token === 'valid-token') {
    next();
  } else {
    res.status(401).json({ error: 'Unauthorized' });
  }
}

// Apply to all /users routes
router.use(authMiddleware);

Combining Multiple Routers

You can have multiple routers for different parts of your API.

Example Directory Structure:

/routes
  - userRoutes.js
  - productRoutes.js
app.js

Mount multiple routers:

app.use('/users', require('./routes/userRoutes'));
app.use('/products', require('./routes/productRoutes'));

Error Handling in Routes

You can define error-handling middleware in your router.

router.get('/error', (req, res, next) => {
  const err = new Error('Something went wrong');
  next(err);
});

// Error handling middleware
router.use((err, req, res, next) => {
  res.status(500).json({ error: err.message });
});

Best Practices

  • Keep each router focused on a single resource (e.g., User, Product).
  • Apply route-specific middleware in the router itself, not globally.
  • Always handle errors gracefully.
  • Use validation middleware (e.g., Zod) to validate inputs at the router level.
  • Mount routers in a hierarchical manner to create a clean URL structure.