Routing & Middleware
Learn Express.js routing patterns and middleware implementation for request processing. This is a foundational concept in server-side JavaScript development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world Node.js experience. Take your time with each section and practice the examples
60 min•By Priygop Team•Last updated: Feb 2026
Express.js Routing
Routing refers to determining how an application responds to a client request to a particular endpoint. Express.js provides a robust routing system that allows you to define routes for different HTTP methods and URL patterns.
Basic Routing
Example
const express = require('express');
const app = express();
// GET route
app.get('/users', (req, res) => {
res.json({ message: 'Get all users' });
});
// POST route
app.post('/users', (req, res) => {
res.json({ message: 'Create new user', data: req.body });
});
// PUT route
app.put('/users/:id', (req, res) => {
res.json({ message: 'Update user', id: req.params.id });
});
// DELETE route
app.delete('/users/:id', (req, res) => {
res.json({ message: 'Delete user', id: req.params.id });
});
// Route with parameters
app.get('/users/:id', (req, res) => {
res.json({ message: 'Get user by ID', id: req.params.id });
});
// Route with query parameters
app.get('/search', (req, res) => {
const { q, page } = req.query;
res.json({ message: 'Search results', query: q, page: page });
});
// Multiple route handlers
app.get('/users/:id',
(req, res, next) => {
console.log('Middleware 1');
next();
},
(req, res, next) => {
console.log('Middleware 2');
next();
},
(req, res) => {
res.json({ message: 'Get user', id: req.params.id });
}
);Express.js Middleware
Example
const express = require('express');
const app = express();
// Application-level middleware
app.use((req, res, next) => {
console.log('Request URL:', req.url);
console.log('Request Method:', req.method);
console.log('Timestamp:', new Date().toISOString());
next();
});
// Middleware for specific routes
app.use('/api', (req, res, next) => {
console.log('API request');
next();
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
// Custom middleware function
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
// Verify token logic here
req.user = { id: 1, name: 'John Doe' };
next();
};
// Using custom middleware
app.get('/protected', authMiddleware, (req, res) => {
res.json({ message: 'Protected route', user: req.user });
});
// Middleware for parsing JSON
app.use(express.json());
// Middleware for serving static files
app.use(express.static('public'));
// CORS middleware
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
next();
});Advanced Routing Patterns
Example
// Advanced routing patterns and techniques
const express = require('express');
const router = express.Router();
// Route chaining
router.route('/users')
.get((req, res) => {
res.json({ message: 'Get all users' });
})
.post((req, res) => {
res.json({ message: 'Create user', data: req.body });
});
// Route with multiple parameters
router.get('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = req.params;
res.json({ userId, postId });
});
// Route with optional parameters
router.get('/users/:id?', (req, res) => {
if (req.params.id) {
res.json({ message: 'Get user by ID', id: req.params.id });
} else {
res.json({ message: 'Get all users' });
}
});
// Route with regex patterns
router.get('/users/:id(\d+)', (req, res) => {
res.json({ message: 'User ID must be numeric', id: req.params.id });
});
// Route with wildcards
router.get('/files/*', (req, res) => {
res.json({ message: 'File path', path: req.params[0] });
});
// Route with multiple callbacks
router.get('/admin',
(req, res, next) => {
console.log('First callback');
next();
},
(req, res, next) => {
console.log('Second callback');
next();
},
(req, res) => {
res.json({ message: 'Admin route' });
}
);
module.exports = router;Middleware Best Practices
- Order matters: Middleware executes in the order it's defined
- Use specific paths: Apply middleware only where needed
- Handle errors properly: Always call next() or send response
- Keep middleware focused: Each middleware should do one thing
- Use async/await: Handle asynchronous operations properly
- Validate input: Check and sanitize request data
- Log appropriately: Use structured logging for debugging
- Performance considerations: Avoid blocking operations in middleware
Mini-Project: Custom Middleware Suite
Example
// Custom middleware suite for Express.js application
const express = require('express');
const app = express();
// 1. Request ID Middleware
const requestId = (req, res, next) => {
req.id = Math.random().toString(36).substr(2, 9);
res.setHeader('X-Request-ID', req.id);
next();
};
// 2. Request Logger Middleware
const requestLogger = (req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`[${req.id}] ${req.method} ${req.url} - ${res.statusCode} (${duration}ms)`);
});
next();
};
// 3. Authentication Middleware
const authenticate = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
// Simple token validation (in real app, use JWT)
if (token === 'Bearer valid-token') {
req.user = { id: 1, name: 'John Doe' };
next();
} else {
res.status(401).json({ error: 'Invalid token' });
}
};
// 4. Rate Limiting Middleware
const rateLimit = (maxRequests = 100, windowMs = 15 * 60 * 1000) => {
const requests = new Map();
return (req, res, next) => {
const ip = req.ip;
const now = Date.now();
const windowStart = now - windowMs;
// Clean old entries
for (const [key, timestamp] of requests.entries()) {
if (timestamp < windowStart) {
requests.delete(key);
}
}
// Check current IP
const ipRequests = Array.from(requests.entries())
.filter(([key, timestamp]) => key.startsWith(ip) && timestamp > windowStart);
if (ipRequests.length >= maxRequests) {
return res.status(429).json({ error: 'Too many requests' });
}
requests.set(`${ip}-${now}`, now);
next();
};
};
// 5. Validation Middleware
const validateUser = (req, res, next) => {
const { name, email, age } = req.body;
const errors = [];
if (!name || name.length < 2) {
errors.push('Name must be at least 2 characters');
}
if (!email || !email.includes('@')) {
errors.push('Valid email is required');
}
if (!age || age < 0 || age > 150) {
errors.push('Age must be between 0 and 150');
}
if (errors.length > 0) {
return res.status(400).json({ errors });
}
next();
};
// 6. Response Time Middleware
const responseTime = (req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
res.setHeader('X-Response-Time', `${duration}ms`);
});
next();
};
// 7. Error Handler Middleware
const errorHandler = (err, req, res, next) => {
console.error(`[${req.id}] Error:`, err);
if (err.name === 'ValidationError') {
return res.status(400).json({ error: 'Validation failed', details: err.message });
}
if (err.name === 'UnauthorizedError') {
return res.status(401).json({ error: 'Unauthorized' });
}
res.status(500).json({ error: 'Internal server error' });
};
// Apply middleware
app.use(requestId);
app.use(requestLogger);
app.use(responseTime);
app.use(express.json());
app.use(rateLimit(10, 60000)); // 10 requests per minute
// Routes
app.get('/', (req, res) => {
res.json({ message: 'Hello World', requestId: req.id });
});
app.get('/protected', authenticate, (req, res) => {
res.json({ message: 'Protected route', user: req.user });
});
app.post('/users', validateUser, (req, res) => {
res.json({ message: 'User created', user: req.body });
});
// Error handling
app.use(errorHandler);
// 404 handler
app.use((req, res) => {
res.status(404).json({ error: 'Route not found' });
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
module.exports = app;