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

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

Contents — Part 7 of 13: Why Order Is Never Optional, In Any Of The Three
Part 7 of 13 · ~1 min

Why Order Is Never Optional, In Any Of The Three

Authorization middleware needs to know who's making the request before it can decide what they're allowed to do — so authentication must run first, in every one of these frameworks, for exactly the same reason. This is the single most common middleware-ordering bug across all three ecosystems, and it's the same bug wearing three different syntaxes.

A second, equally common ordering bug: response-modifying middleware must be registered before the thing whose response it modifies, because of the down-then-up shape. Compression middleware, for instance, needs to run its "after" logic on the final response body — so it needs to be near the top of the list, wrapping everything below it (including the route handler), not near the bottom:

MIDDLEWARE = [
    "django.middleware.gzip.GZipMiddleware",   # wraps everything below — compresses the final response
    "myapp.middleware.LoggingMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
]

If GZipMiddleware were listed after AuthenticationMiddleware instead, it would still work in this particular case (compression doesn't depend on auth having run), but the general principle holds across all three frameworks: "runs on the way out" middleware needs to be registered early enough to actually wrap the code whose output it's modifying.