05 Middleware Basics
title: Middleware Basics in Node.js REST APIs weight: 15 date: 2026-06-28 lastmod: 2026-06-28 description: Learn Express middleware fundamentals including application-level, router-level, error-handling, and third-party middleware for logging, auth, and parsing. tags: [api-development, nodejs]
Express middleware are functions that execute during the request-response cycle with access to the request object, response object, and the next function, forming the backbone of request processing in Node.js REST APIs.
```mermaid
flowchart LR
A[Request] --> B[Middleware 1]
B --> C[Middleware 2]
C --> D[Route Handler]
D --> E[Error Middleware]
E --> F[Response]
B -->|next()| C
C -->|next()| D
D -->|next(err)| E
style A fill:#e1f5fe
style B fill:#fff9c4
style C fill:#fff9c4
style D fill:#c8e6c9
style E fill:#ffcdd2
Middleware functions receive req, res, and next. They can modify req and res, end the response, or call next() to pass control to the next middleware. Express middleware can be application-level (app.use), router-level (router.use), error-handling (4 parameters), or third-party packages.
Think of middleware like an assembly line. Each station (middleware) does one thing: check authentication, parse the body, log the request, add headers. When a station finishes its job, it passes the product (request) to the next station via next().
Example: Custom Logger Middleware
const express = require('express');
const app = express();
// Application-level middleware
app.use((req, res, next) => {
const start = Date.now();
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`[${req.method} ${req.url}] ${res.statusCode} - ${duration}ms`);
});
next();
});
app.get('/api/test', (req, res) => {
res.json({ message: 'Middleware test' });
});
app.listen(3000);
Expected output:
[2026-06-28T10:00:00.000Z] GET /api/test
[GET /api/test] 200 - 5ms
Example: Authentication Middleware
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token.replace('Bearer ', ''), process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
return res.status(401).json({ error: 'Invalid token' });
}
};
// Protect specific routes
app.get('/api/users/me', authMiddleware, (req, res) => {
res.json({ user: req.user });
});
// Protect all routes in a router
router.use(authMiddleware);
Example: Error-Handling Middleware
// Error-handling middleware has 4 parameters
app.use((err, req, res, next) => {
console.error('Unhandled error:', err);
const statusCode = err.statusCode || 500;
const message = err.isOperational ? err.message : 'Internal server error';
res.status(statusCode).json({
error: {
message,
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
}
});
});
// Usage: throw errors from routes
app.get('/api/error', (req, res, next) => {
const error = new Error('Something broke');
error.statusCode = 400;
error.isOperational = true;
next(error);
});
Common Mistakes
- Not calling next() — Forgetting next() hangs the request. The client eventually times out with no response. Always call next() or end the response.
- Placing middleware after routes — Middleware defined after routes never executes for those routes. Application middleware should be defined before routes.
- Modifying req or res without calling next — If you modify the request or response, call next() afterward so subsequent middleware can use the changes.
- Not handling errors in async middleware — Async middleware that throws must call next(err) or the error is unhandled. Use express-async-errors to catch async rejections.
- Adding unnecessary middleware — Every middleware adds processing time. Only add middleware that provides value for your API.
Practice Questions
- What are the three arguments every middleware function receives?
- What is the difference between application-level and router-level middleware?
- How do you create error-handling middleware?
- What happens if you forget to call next() in middleware?
- Challenge: Create a middleware pipeline with 4 custom middleware: request logger, response timer, API version checker (header), and rate limiter. Test the pipeline with a simple endpoint.
FAQ
Mini Project
Create a middleware stack for an Express API with: request logger (method, URL, duration), security headers (helmet), CORS, JSON body parser, authentication checker (for protected routes), request validator (check required headers), and error handler. Test with a protected and unprotected route.
What's Next
Now learn about request parsing in Building REST APIs with Node.js.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro