FastAPI cookbook · Intermediate
Call external APIs with retries and timeouts from FastAPI
Integrate a flaky third-party API without blocking workers or hammering it during outages.
Approach
Share one httpx.AsyncClient (created in lifespan) with explicit timeouts and connection limits. Retry idempotent calls on transient errors with exponential backoff + jitter using tenacity, honor Retry-After on 429, and translate failures into domain errors (e.g., 503 to your caller).
Solution
import httpx
from tenacity import AsyncRetrying, retry_if_exception, stop_after_attempt, wait_exponential_jitter
RETRYABLE_STATUS = {429, 502, 503, 504}
def is_transient(exc: BaseException) -> bool:
if isinstance(exc, (httpx.ConnectError, httpx.ReadTimeout)):
return True
return isinstance(exc, httpx.HTTPStatusError) and exc.response.status_code in RETRYABLE_STATUS
async def get_exchange_rate(http: httpx.AsyncClient, base: str, quote: str) -> float:
try:
async for attempt in AsyncRetrying(
retry=retry_if_exception(is_transient),
wait=wait_exponential_jitter(initial=0.2, max=3),
stop=stop_after_attempt(3),
reraise=True,
):
with attempt:
resp = await http.get(f"/rates/{base}/{quote}")
resp.raise_for_status()
return resp.json()["rate"]
except (httpx.HTTPError,) as exc:
raise RatesUnavailable() from exc
# lifespan: app.state.http = httpx.AsyncClient(base_url=..., timeout=httpx.Timeout(5, connect=2),
# limits=httpx.Limits(max_connections=50))
Pitfalls
- httpx default timeout (5s) is fine, but
timeout=Nonehangs forever. - Retrying non-idempotent POSTs.
- A new client per request (no connection pooling).
Variations
- Add a circuit breaker (e.g.,
purgatoryoraiobreaker) for critical dependencies. - Cache successful responses briefly to absorb spikes.
Further reading: HTTPX: Timeouts
Reference: https://www.python-httpx.org/advanced/timeouts/
More FastAPI recipes
- Add liveness and readiness endpoints to FastAPI
- Add OpenTelemetry tracing to FastAPI
- Add request IDs and structured logs to FastAPI
- Build a WebSocket chat endpoint in FastAPI
- Cache FastAPI responses in Redis
- Implement role-based access control in FastAPI
- Isolate tenants in a multi-tenant FastAPI app
- Paginate with cursors in FastAPI