The Middleware Pattern is a structural design pattern commonly used in web development, especially in web servers and applications. It allows developers to add layers of processing to requests and responses, making the code more modular, reusable, and easier to maintain. Middleware functions can perform a variety of tasks such as logging, authentication, data parsing, and error handling before sending the response to the client or passing the request to another middleware function.
Here’s a simple example of the Middleware Pattern in a Node.js application using Express.js, a popular web application framework. This example demonstrates how middleware can be used for logging requests, parsing JSON payloads, and implementing basic authentication.
Step 1: Set Up Your Project
First, you need to set up a Node.js project and install Express:
mkdir express-middleware-example
cd express-middleware-example
npm init -y
npm install express
Step 2: Create Your Server with Middleware
Create a file named server.js
and add the following code to demonstrate the Middleware Pattern:
const express = require('express');
const app = express();
const PORT = 3000;
// Middleware for logging requests
app.use((req, res, next) => {
console.log([${new Date().toISOString()}] ${req.method} ${req.url}
);
next(); // Pass control to the next middleware
});
// Built-in middleware for parsing JSON bodies
app.use(express.json());
// Middleware for basic authentication
app.use((req, res, next) => {
const auth = { login: 'admin', password: 'secret' }; // Example credentials
const b64auth = (req.headers.authorization || '').split(' ')[1] || '';
const [login, password] = Buffer.from(b64auth, 'base64').toString().split(':');
// Verify login and password are set and correct
if (login && password && login === auth.login && password === auth.password) {
// Access granted…
return next();
}
// Access denied…
res.set('WWW-Authenticate', 'Basic realm="401"') // Change this as required.
.status(401).send('Authentication required.'); // Custom message.
});
// Route handler as the final "middleware"
app.get('/', (req, res) => {
res.send('Hello, World! You are authenticated.');
});
app.listen(PORT, () => console.log(Server running on http://localhost:${PORT}
));
Step 3: Run Your Server
Run your server using Node.js:
node server.js
In this example:
- The first middleware logs the date, HTTP method, and URL of each request.
- The
express.json()
middleware is used to automatically parse JSON-formatted request bodies. - The third middleware implements a basic form of authentication. It checks for a specific username and password in the request’s
Authorization
header. If the credentials are not present or incorrect, it denies access and returns a 401 status code. Otherwise, it callsnext()
to pass control to the next middleware. - Finally, a route handler for the root path (
/
) sends back a greeting message to the authenticated user.
This setup showcases how middleware functions can be chained together to process requests and how each middleware can perform its specific task, either modifying the request/response objects, terminating the request-response cycle, or calling the next middleware in the stack.