Warming up the neural circuits...
By the end of this chapter you will:
Most developers learn FastAPI or Django before they learn the actual web contract.
That works until things break:
Frameworks are wrappers. This chapter removes the wrapper and shows the protocol-level reality underneath.
When you understand request flow, method semantics, headers, and server interfaces, you stop guessing and start debugging from first principles.
POST /users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer <token>
{"name": "Ava", "email": "ava@example.com"}Response shape:
HTTP/1.1 201 Created
Content-Type: application/json
Location: /users/42
{"id": 42, "name": "Ava", "email": "ava@example.com"}Every framework feature still maps to this shape: method, path, headers, body, status code.
| Method | Typical meaning | ? |
|---|---|---|
| GET | Read resource | Yes |
| POST | Create action/resource | Usually no |
| PUT | Replace resource | Yes |
| PATCH | Partial update | Usually yes if designed carefully |
| DELETE | Remove resource | Yes |
Idempotent means repeating the same request has the same final . This matters for client retries, load balancers, and incident recovery.
Minimal practical set:
Good APIs make status codes predictable so clients can branch correctly.
def app(environ, start_response):
path = environ.get("PATH_INFO", "/")
if path == "/health":
status = "200 OK"
body = b"healthy"
else:
async def app(scope, receive, send):
if scope["type"] != "http":
return
body = b"hello from asgi"
await send(
{
"type": "http.response.start
Latency can come from any layer. Not every performance issue is Python code.
FastAPI, Flask, and Django provide routing, validation, dependency injection, and middleware abstractions. They do not replace HTTP semantics. They encode them.
| Situation | Better default | Why |
|---|---|---|
| Simple internal | WSGI or ASGI both fine | Constraints are low; ops familiarity matters most |
| Many concurrent I/O calls | ASGI | Async handlers reduce idle wait overhead |
| Websocket/streaming endpoints | ASGI | Native support for long-lived async protocols |
| Team already deep in Django sync stack | WSGI first, ASGI selectively | Lower migration risk while gaining wins where needed |
| Mistake | Why it hurts | Better move |
|---|---|---|
| Returning 200 for every outcome | Clients cannot automate error handling | Use semantic status codes |
| Treating POST as retry-safe | Duplicate writes during retries | Use idempotency strategy for critical writes |
| Assuming async fixes CPU bottlenecks | Event loops do not make CPU-bound work faster | Offload CPU-heavy tasks to workers/processes |
| Ignoring timeouts at client/server boundaries | Hanging requests and resource leaks | Define and monitor timeout budgets |
| Blaming framework first | Root cause may be DNS, DB, proxy, or TLS | Trace full request lifecycle with logs and metrics |
Successful create, missing auth, bad payload shape, not found, conflict201, 401, 400 or 422, 404, 409 with reasonsPATH_INFO from environ200 for /health, 404 otherwiseProxy logs + app logs + DB query timingLatency decomposition and top bottleneckService with bursty I/O and upcoming websocket featureMigration recommendation with tradeoffsLegacy API response wrapperConsistent 2xx/4xx/5xx behaviorBeginner:
"What is the difference between 401 and 403?"
401 means authentication is missing or invalid. 403 means authenticated but not permitted.
"Why does idempotency matter in HTTP APIs?"
It allows safe retries without changing final state unpredictably.
Senior:
"When would you choose ASGI over WSGI in a mature Python stack?"
When concurrency is I/O-heavy, websocket support is required, or async architecture yields measurable latency/cost gains.
"How do you debug a high p95 latency endpoint systematically?"
Build end-to-end timing at each hop, isolate dominant segment, and optimize with instrumentation-backed hypotheses.
HTTP = method + path + headers + body -> status + headers + body
WSGI = sync callable(environ, start_response)
ASGI = async callable(scope, receive, send)
Retry-safe behavior depends on idempotency, not on framework choice.Which interface is designed for async Python web applications and protocols like WebSockets?
WSGI is request-in, response-out, one call per request. It is simple and stable but not natively built for long-lived async connections.
ASGI supports async request handling and additional protocols such as websockets without changing deployment philosophy.