In this lesson, you will learn how to structure a request-processing pipeline where multiple functions sequentially decorate or transform a request object before it reaches the final handler.
The Middleware Pipeline
Think of an HTTP request as a package traveling down a conveyor belt. In a raw Node.js environment, the request arrives at your server as a raw stream of data. A "Middleware Pattern" allows you to set up stations along that belt. Each station—or middleware—has the opportunity to inspect the request, modify its properties, or even halt the process entirely.
By the time the request reaches your core business logic (the final "handler"), the request object has been "warmed up" and populated with everything the handler needs to do its job.
Constructing the Pipeline
To implement this, you create a chain of functions. Each function accepts the request, the response, and a next callback. Calling next() moves the process to the subsequent function in the pipeline. If a middleware forgets to call next(), the request hangs, effectively stalling the conveyor belt.
Consider this simplified pattern for adding a timestamp to a request:
const addTimestamp = (req, res, next) => {
req.receivedAt = Date.now();
next(); // Pass the baton to the next station
};
const logger = (req, res, next) => {
console.log(`Request arrived at: ${req.receivedAt}`);
next();
};
// Pipeline execution
const pipeline = [addTimestamp, logger];
function runPipeline(req, res, handler) {
let index = 0;
function next() {
if (index < pipeline.length) {
pipeline[index++](req, res, next);
} else {
handler(req, res);
}
}
next();
}
In this example, addTimestamp transforms the req object by attaching a new property. By the time handler is executed, it can trust that req.receivedAt exists. This decoupling keeps your primary request logic clean, as it no longer needs to worry about mundane tasks like logging or parsing; it simply consumes the prepared object.
Key Takeaway: Middleware transforms the request through a sequence of functions, ensuring the final handler receives a fully enriched object without being cluttered by pre-processing logic.