Request lifecycle — the shape they all share
Every framework does the same dance: parse → route → middleware → handler → serialize → respond. Learn the shape once, read any framework faster.
Every web framework executes the same seven steps per request: (1) receive bytes, (2) parse HTTP, (3) route to a handler, (4) run middleware, (5) run the handler, (6) serialize the response, (7) send bytes back. The syntax differs; the shape doesn't.
Middleware is the 'onion' model: each layer wraps the next. A typical chain: request-ID → logging → CORS → auth → rate-limit → handler → response-logging. Each layer can inspect, modify, or short-circuit (e.g., auth fails → return 401 without calling the handler).
Order matters: app.use(logger); app.use(auth) logs before authenticating — you see unauthorized requests in logs. Swapping them means only authenticated requests are logged. Not a bug, just a choice — but you need to MAKE the choice consciously.
Once you internalize this skeleton, reading a new framework becomes 10× faster. Express's app.use(), Django's MIDDLEWARE list, FastAPI's app.add_middleware, Rails's config.middleware, Next.js's middleware.ts — all the same concept.
Common hooks to learn in ANY framework you pick up: before-request (global preprocessing), after-request (logging, response headers), exception handler (map domain errors to HTTP codes), route decorator (associate URL + method with handler). Find these four in any framework and you can work in it.
Grounded on https://docs.djangoproject.com/en/stable/topics/http/middleware/
Next up
ORM & data layer patterns
Active Record, Data Mapper, Query Builder, raw SQL. The data access pattern your framework ships shapes how you think about persistence.