Understanding Middleware in Express
In Express, Middleware is a function that runs after the incoming request is received and before the final response is sent. It has access to the Request (req), Response (res), and the next function in the cycle.
1. How Middleware Worksโ
Think of Middleware as a series of checkpoints. Each middleware can:
- Execute any code.
- Make changes to the
reqandresobjects. - End the request-response cycle (e.g., if a user isn't logged in).
- Call the
next()function to pass control to the next middleware.
app.use((req, res, next) => {
console.log("This runs for every request!");
next(); // Passes control to the next middleware or route handler
});
2. Types of Middlewareโ
1. Built-in Middlewareโ
Express comes with some tools already included. The most common one is express.json(), which helps your server understand JSON data sent by a frontend (like a React app).
app.use(express.json()); // Essential for modern apps!
2. Third-Party Middlewareโ
The community has built amazing tools that you can install via NPM.
- Morgan: Logs every request so you can see who is visiting your site.
- Cors: Allows your frontend to talk to your backend safely.
- Dotenv: Helps manage "secret" environment variables.
npm install morgan
Now, let's use it in our server.js:
const morgan = require('morgan');
app.use(morgan('dev')); // Now every request shows up in your terminal!
3. Custom Middlewareโ
You can write your own middleware to do anything you want! This is great for things like checking if a user is an admin or logging the time of a request.
3. Building Your First Custom Middlewareโ
Let's create a "Logger" that prints the URL and the current time whenever someone visits our site.
const myLogger = (req, res, next) => {
const currentTime = new Date().toLocaleTimeString();
console.log(`[${currentTime}] Request made to: ${req.url}`);
// CRITICAL: You must call next() or the browser will hang forever!
next();
};
// Apply it to the whole app
app.use(myLogger);
4. Global vs. Specific Middlewareโ
At CodeHarborHub, we teach you to be precise with your code. You don't always want middleware to run on every page.
Global Middlewareโ
Runs for every single route in your app.
app.use(express.json());
Specific Middlewareโ
Only runs for a specific route. This is perfect for "Protected Routes" (e.g., only users who are logged in can see /dashboard).
const checkAuth = (req, res, next) => {
const isAuthorized = true; // In real life, check for a token
if (isAuthorized) {
next();
} else {
res.status(401).send("Access Denied!");
}
};
app.get('/dashboard', checkAuth, (req, res) => {
res.send("Welcome to your secret dashboard!");
});
5. The Importance of next()โ
If you forget to call next(), your request will get "stuck" in that middleware. The user's browser will show a spinning loading icon until it eventually times out. Always remember: Middleware is a relay raceโyou must pass the baton!
Practice: The "Maintenance Mode" Challengeโ
Try to create a middleware that prevents anyone from visiting your site.
- Create a middleware function.
- Instead of calling
next(), it should send a message:"Site under maintenance. Check back later!". - Apply it to your app and try to visit any route.
Express runs middleware in the order you write them in your code. If you put your error-handling middleware at the top, it won't catch any errors from the routes below it. Always place global middleware and routes first, and error handlers last.