Middleware Architecture

Express is essentially a series of **middleware** function calls. Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle.

What Middleware Can Do:

  • Execute any code.
  • Make changes to the request and the response objects.
  • End the request-response cycle.
  • Call the next middleware function in the stack.

The Lifecycle

app.use((req, res, next) => {
  console.log('1. Middleware ran');
  next(); // Passes control to next handler
});

app.get('/', (req, res) => {
  console.log('2. Route handler ran');
  res.send('Done'); // Ends the cycle
});

Configuring Middleware Execution

If you don't call next(), the request will hang and the client will timeout. The only alternative to calling next() is to send a response back using res.send(), res.json(), etc.

Modular Design: Because Express uses this onion-like architecture, you can easily plug in security, logging, and data parsing tools without cluttering your main logic.

Synchronous vs Asynchronous Middleware

Modern Express supports async middleware functions. This is perfect for checking a database or calling an external API before a request reaches the route.

app.use(async (req, res, next) => {
  const user = await User.findById(req.session.userId);
  req.user = user;
  next();
});