1. Async HTTP calls with httpx
Start with the contract: make inputs, outputs and failure behavior explicit before adding infrastructure. This keeps the feature easy to reason about and gives tests a stable boundary.
2. Timeouts, retries and idempotency
Apply the pattern through a small vertical slice. Keep framework wiring at the edge and business decisions in focused functions or services that can be tested without starting the whole application.
import httpx
timeout = httpx.Timeout(2.0, connect=0.5)
async with httpx.AsyncClient(timeout=timeout) as client:
response = await client.get(f"{USERS_URL}/users/{user_id}")
response.raise_for_status()3. Circuit breakers and graceful degradation
Treat failure paths as part of the design. Add bounded resource usage, meaningful errors and a verification step so the behavior remains dependable under real production conditions.
4. Hands-on Exercise
Build the feature
Split user profiles into a second service and call it with strict timeouts. Return a useful degraded response when the dependency is unavailable.
Definition of done
- The happy path works through the real HTTP boundary.
- At least one failure path is handled and tested.
- Configuration and secrets stay outside source code.
- The README explains how to run and verify the result.
5. Knowledge Check
Why is retrying every failed POST dangerous?
Show answer
A retry can repeat a non-idempotent side effect; use an idempotency key or retry only operations known to be safe.