Understanding Middleware in Express.js with Practical Implementation

Understanding Middleware in Express.js with Practical Implementation

Introduction

Express.js is a popular web framework for Node.js that simplifies the process of building web applications and APIs. One of the most powerful features of Express is middleware, which allows developers to handle requests in a modular and reusable way. In this blog post, we’ll explore what middleware is, its role in Express.js, and how to implement it using an example authentication system.


What is Middleware?

Middleware functions in Express.js are functions that execute before the final request handler. These functions have access to the request (req) and response (res) objects, as well as the next() function, which is used to pass control to the next middleware in the stack.

Middleware is commonly used for:

  • Request logging

  • Parsing request bodies (e.g., JSON, form data)

  • Implementing authentication and authorization

  • Handling errors

  • Modifying request and response objects

Types of Middleware in Express.js

  1. Built-in Middleware (e.g., express.json(), express.urlencoded()).

  2. Third-party Middleware (e.g., body-parser, cors).

  3. Custom Middleware (which we’ll implement below).


Implementing Middleware in Express.js

Let’s walk through an example where we implement two middleware functions:

  1. Authentication Middleware to check user credentials.

  2. Data Processing Middleware to combine username and password into a single variable.

Project Setup

Ensure you have Node.js and Express installed. If not, install them using:

npm install express body-parser

Code Implementation

import express from "express";
import bodyParser from "body-parser";
const app = express();
const port = 3000;
import { dirname } from "path";
import { fileURLToPath } from "url";

const __dirname = dirname(fileURLToPath(import.meta.url));
app.use(bodyParser.urlencoded({ extended: true }));

var userAuthorized = false;
var combinedName = '';

// Middleware for Authentication
function secretDoor(req, res, next) {
    console.log(req.body);
    const { username, password } = req.body;
    if (username === 'admin' && password === '123') {
        userAuthorized = true;
    }
    next();
}

// Middleware for Processing User Data
function combined(req, res, next) {
    console.log(req.body);
    combinedName = req.body['username'] + req.body['password'];
    next();
}

// Using Middleware in the App
app.use(express.static('public'));
app.use(secretDoor);
app.use(combined);

// Route for Serving Homepage
app.get('/', (req, res) => {
    res.sendFile(__dirname + '/index.html');
});

// Route for Checking Authentication
app.post('/check', (req, res) => {
    if (userAuthorized) {
        res.sendFile(__dirname + '/secret.html');
    } else {
        res.send(`Your combined name is ${combinedName}`);
    }
});

app.listen(port, () => {
    console.log("Server is up and running");
});

How Middleware Works in This Code

1. Authentication Middleware (secretDoor)

  • Extracts username and password from the request body.

  • If the credentials match admin and 123, it sets userAuthorized = true.

  • Calls next() to pass control to the next middleware or route handler.

2. Data Processing Middleware (combined)

  • Concatenates username and password into a combinedName variable.

  • Calls next() to pass control to the next function.

3. Middleware Usage

  • app.use(secretDoor); → Ensures authentication middleware runs before handling requests.

  • app.use(combined); → Extracts and combines credentials before processing.


Conclusion

Middleware is a powerful concept in Express.js that allows developers to modularize and streamline their application logic. In this example, we created two middleware functions—one for authentication and another for data processing—demonstrating how they work together before reaching the final route handler.

By mastering middleware, you can build scalable and maintainable applications with Express.js. Try implementing your own middleware functions to handle logging, error handling, or API rate limiting!