The Request/Response Lifecycle
What actually happens between a client sending a request and a backend sending back a response.
2 min read
Every interaction between a client (a browser, a mobile app, another server) and a backend follows the same basic shape: a request goes out, something happens on the server, and a response comes back. Understanding that lifecycle in detail is the foundation for debugging, designing APIs, and reasoning about performance.
The stages
- DNS resolution — the client turns a domain name (
api.example.com) into an IP address. - Connection setup — a TCP connection is established, and for HTTPS, a TLS handshake negotiates encryption.
- Request sent — the client sends an HTTP request: a method, a path, headers, and optionally a body.
- Server receives and routes — the backend's web server or framework matches the request's method and path to a specific piece of code (a route handler).
- Middleware runs — cross-cutting logic executes before the handler: parsing the body, checking authentication, logging.
- Handler executes — the actual application logic runs: reading/writing a database, calling another service, applying business rules.
- Response is built — a status code, headers, and a body (often JSON) are assembled.
- Response sent back — the server sends it over the same connection, and the client processes it.
A concrete example
Client Server
|--- GET /api/users/42 ---------------->|
| | 1. Router matches GET /api/users/:id
| | 2. Middleware checks auth token
| | 3. Handler queries the database
| | 4. Handler builds JSON response
|<--- 200 OK, {"id":42,"name":"Ada"} ---|
If any stage fails — the token is invalid, the database is unreachable, the user doesn't exist — the backend short-circuits and returns an appropriate error response instead of continuing down the chain.
Why "stateless" matters here
Most backend APIs are designed to be stateless: each request carries everything the server needs to handle it (like an auth token), and the server doesn't rely on remembering anything from a previous request in its own memory. This matters enormously for scaling — if any server in a pool can handle any request without needing to recall prior interactions, you can add more servers behind a load balancer without special coordination. Lesson topics later in this course, like sessions and horizontal scaling, both come back to this idea.
Latency adds up
Each stage of the lifecycle takes real time — DNS lookups, network round trips, database queries — and those costs stack. A backend that makes three sequential database calls where one would do isn't just inefficient in theory; a user waiting on a spinner feels every one of those round trips. Keeping this lifecycle in mind is what separates code that merely works from code that responds quickly under real load.
Next: the HTTP methods and status codes that give every request and response in this lifecycle its actual meaning.