CodeOath
← All posts
Architecture & Patterns55 min total · 13 parts

Middleware Pipelines Compared: ASP.NET Core, Express.js, and Django

Contents — Part 2 of 13: The Shared Mental Model
Part 2 of 13 · ~1 min

The Shared Mental Model

Diagram of a request passing down through middleware layers, then a response passing back up

A request enters at the top of the chain and moves down, layer by layer. Each middleware does its job, then either:

  1. Passes control to the next layer (most common — logging, then keep going), or
  2. Short-circuits and returns a response immediately (e.g. authentication middleware rejecting an unauthenticated request with a 401, never reaching the route handler at all).

Once something does generate a response (usually the final route handler), it travels back up through the same layers in reverse — which is why logging middleware often logs both the incoming request and the outgoing response status, from the same place in the code. This "wrap everything below me" shape is sometimes called the onion model: each middleware is a layer of the onion, the route handler is the core, and a single function call travels all the way down to the core and all the way back out.

Why this pattern exists at all

Every real HTTP server needs a set of cross-cutting concerns applied to most or all requests — logging, authentication, compression, CORS headers, error handling — without hardcoding all of that into every single route handler. Middleware exists specifically to let those concerns be written once, in one place, and composed together in a declared order, rather than duplicated (or forgotten) at the top of every handler function.