Middleware Chaining in Express.js and Node.js

Rana Muzamil
3 min readMar 29, 2024

--

Middleware Chaining in Express.js and Node.js

As a software engineer, adding complex features to our apps feels like making a cool piece of art. So, I was working on this project and ran into a situation. I needed to ensure users finished setting up their profiles before going to specific parts of the app. It’s a common problem! How do you make sure of that without making your code messy?

Imagine middleware in Express.js as the hero in shining armor for Node.js apps.

Middleware, for those who don’t know, are like the guards of our routes. They check, change, or stop incoming requests. But what if I told you there’s a way to use middleware smoothly across many routes? Yes, developers, it’s time to talk about chaining middleware.

Picture this: You’re looking at your code, trying to figure out the best way to ensure users finish setting up their profiles. You could scatter middleware calls in every route where this check is needed, but that’s not very neat, right? Instead, let me show you a cleaner, more organized solution — chaining middleware.

const express = require('express');
const app = express();

function checkProfile(req, res, next) {
if (req.user.profileComplete) {
next();
} else {
res.status(403).send('Please complete your profile');
}
}

app.use(checkProfile);

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

app.get('/dashboard', (req, res) => {
res.send('Welcome to your dashboard!');
});

// Routes where profile check is not required
app.get('/public', (req, res) => {
res.send('This is a public page');
});

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

In the snippet above, we’ve defined a middleware function checkProfile that inspects whether the user's profile is complete. But here's the kicker – instead of applying this middleware to each route, we simply use app.use(checkProfile). This single line acts as a gateway, ensuring that every subsequent route is guarded by our profile completion check.

Now, every time a request hits our server, checkProfile springs into action, either granting passage to the requested route or redirecting the user to complete their profile if it's not yet done. Neat, isn't it?

But wait, there’s more! Chaining middleware isn’t just about applying a single middleware function. Oh no, you can stack ’em up like building blocks, each one adding its layer of functionality to the request-response cycle.

function logTimestamp(req, res, next) {
console.log(`Request received at ${new Date()}`);
next();
}

function authenticate(req, res, next) {
if (req.user) {
next();
} else {
res.status(401).send('Unauthorized');
}
}

app.use(logTimestamp, authenticate);

In this example, we’ve chained two middleware functions — logTimestamp and authenticate. First, the logTimestamp middleware logs the timestamp of each incoming request. Then, the authenticate middleware checks if the user is authenticated before allowing access to protected routes.

With chaining middleware, you can orchestrate a symphony of functionalities, each harmonizing with the next to create a seamless user experience.

So there you have it, fellow developers — the power of chaining middleware in Express.js and Node.js. With this newfound knowledge, go forth and streamline your code, weaving together functionalities with the elegance of a seasoned artisan.

In this article, we embarked on a journey through the enchanting world of middleware in Express.js and Node.js. We learned how to leverage the magic of chaining middleware to elegantly enforce requirements across multiple routes, simplifying our code and enhancing the user experience. Armed with this knowledge, you’re now equipped to tackle even the most complex scenarios with finesse. Until next time, happy coding!

--

--

Rana Muzamil
Rana Muzamil

No responses yet