Middleware in Express.js


Middleware in Express.js and Enhancing the Movie API Project
1. Introduction to Middleware
What is Middleware?
In Express, middleware functions are functions that execute during the request-response cycle, providing a way to modify requests and responses or handle specific tasks before they reach the main route handlers.
Why Use Middleware?
Middleware helps streamline and manage common tasks across your application:
Request Logging: Tracking incoming requests.
Security Enhancements: Adding headers or restricting access.
Data Validation and Parsing: Ensuring data integrity.
Error Handling: Managing errors consistently.
Types of Middleware in Express
Application-level Middleware: Applied at the app level to manage all requests.
Router-level Middleware: Applied only to specific routes or routers.
Built-in Middleware: Provided by Express for common tasks.
Third-party Middleware: Libraries installed from npm for specialized functions.
Custom Middleware: Custom functions for specific logic in your application.
2. Middleware Types Explained with Examples
1. Application-level Middleware
Application-level middleware is applied to every request within an application. You define it using app.use()
.
app.use(express.json()); // Parses incoming JSON data
app.use(cors()); // Enables CORS to allow cross-origin requests
2. Router-level Middleware
Router-level middleware is used within specific routers, targeting only those routes. You define it using router.use()
.
const router = express.Router();
router.use((req, res, next) => {
console.log('Router-level middleware');
next();
});
3. Built-in Middleware
Express includes several built-in middleware functions:
express.json(): Parses JSON payloads in incoming requests.
express.urlencoded(): Parses URL-encoded data (like form submissions).
4. Third-party Middleware
Many npm packages provide middleware functionality:
CORS (
cors
): Controls cross-origin resource sharing.Helmet (
helmet
): Adds security headers.Morgan (
morgan
): Logs HTTP requests.
5. Custom Middleware
Custom middleware is written specifically to meet application needs. For example, a middleware to check if a user is authenticated.
const authMiddleware = (req, res, next) => {
if (!req.headers.authorization) {
return res.status(401).send('Unauthorized');
}
next();
};
3. Movie Project Enhancements Using Middleware
Step 1: Application-Level Middleware
Enhance the Movie API project by adding application-level middleware for data size limits, security headers, CORS, and logging.
Setting Up Middleware in index.js
Limit JSON Body Size and URL-encoded Body Size:
- Use
express.json()
andexpress.urlencoded()
to limit the maximum request body size.
- Use
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import morgan from 'morgan';
import movieRoutes from './routes/movies.js';
const app = express();
const PORT = 3000;
// Limit JSON body size to 1MB
app.use(express.json({ limit: '1mb' }));
// Limit URL-encoded body size to 1MB
app.use(express.urlencoded({ limit: '1mb', extended: true }));
// CORS to allow requests only from the frontend
app.use(cors({ origin: 'http://localhost:3000' }));
// Security headers for all routes
app.use(helmet());
// HTTP request logging
app.use(morgan('combined'));
app.use('/movies', movieRoutes);
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
Explanation of Middleware Functions:
express.json({ limit: '1mb' })
: Limits incoming JSON data to 1MB, protecting against payload abuse.express.urlencoded({ limit: '1mb', extended: true })
: Limits URL-encoded data (used in forms) to 1MB.cors({ origin: '
http://localhost:3000
' })
: Restricts API access to your frontend’s origin.helmet()
: Adds security headers to prevent certain attacks (e.g., clickjacking, XSS).morgan('combined')
: Logs HTTP requests for monitoring.
Step 2: Router-Level Middleware
Let’s add a dummy authentication middleware to restrict access to the movie routes, simulating basic authentication.
Dummy Authentication Middleware:
- Create a middleware function that checks for an
Authorization
header with a dummy token.
- Create a middleware function that checks for an
// routes/movies.js
import express from 'express';
import { getAllMovies, getSingleMovie, createMovie } from '../controllers/movieController.js';
const router = express.Router();
// Dummy Auth Middleware
const dummyAuthMiddleware = (req, res, next) => {
const authHeader = req.headers.authorization;
if (authHeader === 'Bearer my-secret-token') {
next();
} else {
res.status(401).json({ error: 'Unauthorized' });
}
};
// Apply auth middleware to all movie routes
router.use(dummyAuthMiddleware);
router.get('/', getAllMovies);
router.get('/:id', getSingleMovie);
router.post('/', createMovie);
export default router;
Explanation:
dummyAuthMiddleware
: Checks for an authorization header. If it’s missing or incorrect, a401 Unauthorized
response is sent.This middleware simulates authentication and can be replaced with real auth logic as needed.
4. HTTP Status Codes and Error Handling Best Practices
Using correct HTTP status codes helps inform clients of the response type and any errors encountered. Here’s a quick reference:
200 OK: Success.
201 Created: Successfully created a new resource.
400 Bad Request: Client error due to invalid data.
401 Unauthorized: Access denied due to lack of authorization.
404 Not Found: Resource not found.
500 Internal Server Error: Server-side error.
Best Practices for Error Handling:
Return specific error messages for client-side errors.
Use
try/catch
for operations that might fail, such as file reads and writes.Create a global error-handling middleware to handle unexpected errors.
Global Error-Handling Middleware
Define a global error handler as the last middleware in index.js
:
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
5. Full Movie API Project with Middleware Enhancements
Here’s the final structure and code for an enhanced Movie API project with all middleware integrated.
Project Structure
movie-api/
├── controllers/
│ └── movieController.js
├── routes/
│ └── movies.js
├── middleware/
│ └── dummyAuth.js # Router-level auth middleware
├── db.json # JSON file serving as database
├── index.js # Main server file
└── package.json
Final index.js
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import morgan from 'morgan';
import movieRoutes from './routes/movies.js';
const app = express();
const PORT = 3000;
// Application-level middleware
app.use(express.json({ limit: '1mb' }));
app.use(express.urlencoded({ limit: '1mb', extended: true }));
app.use(cors({ origin: 'http://localhost:3000' }));
app.use(helmet());
app.use(morgan('combined'));
// Routes
app.use('/movies', movieRoutes);
// Global error-handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
dummyAuth.js
(Router-Level Middleware)
const dummyAuthMiddleware = (req, res, next) => {
const authHeader = req.headers.authorization;
if (authHeader === 'Bearer my-secret-token') {
next();
} else {
res.status(401).json({ error: 'Unauthorized' });
}
};
export default dummyAuthMiddleware;
movies.js
(Route Definitions)
import express from 'express';
import { getAllMovies, getSingleMovie, createMovie } from '../controllers/movieController.js';
import dummyAuthMiddleware from '../middleware/dummyAuth.js';
const router = express.Router();
// Apply dummy auth middleware to all routes
router.use(dummyAuthMiddleware);
router.get('/', getAllMovies);
router.get('/:id', getSingleMovie);
router.post('/', createMovie);
export default router;
Summary
Middleware provides a way to handle repetitive tasks across requests, improving maintainability.
Types of middleware include application-level, router-level, built-in, third-party, and custom middleware.
In the Movie API project, we used application-level middleware for data size limits, security headers, CORS, and logging.
Router-level middleware, like dummy authentication, restricts access to specific routes.
HTTP status codes and structured error handling communicate response outcomes clearly.
Subscribe to my newsletter
Read articles from Anjali Saini directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Anjali Saini
Anjali Saini
I am an Enthusiastic and self-motivated web-Developer . Currently i am learning to build end-to-end web-apps.