requests & httpx — Calling APIs
Intermediaterequests is the de-facto HTTP client: get/post with params and JSON, status checks with raise_for_status, timeouts ALWAYS, and Sessions for connection reuse.
Overview
Every backend consumes other services — payment gateways, auth providers, internal microservices — and in Python that means requests (sync) or httpx (same API, plus async). The non-negotiables of production HTTP: pass timeout= on every call (the default is wait-forever), check responses with raise_for_status(), send/receive JSON via json= and .json(), and reuse a Session for connection pooling and shared headers. These five habits are what code reviewers look for first.
GET & POST with JSON
params= builds the query string safely; json= serializes the body and sets Content-Type. Inspect status_code, headers and .json(). raise_for_status() turns 4xx/5xx into exceptions.
import requests
# GET with query parameters
r = requests.get(
"https://api.github.com/search/repositories",
params={"q": "fastapi", "per_page": 3}, # ?q=fastapi&per_page=3
timeout=10, # ALWAYS set a timeout
)
r.raise_for_status() # raises on 4xx/5xx
data = r.json() # parsed JSON body
print(r.status_code, data["total_count"])
# POST JSON
payload = {"name": "Asha", "plan": "pro"}
r = requests.post(
"https://httpbin.org/post",
json=payload, # serializes + sets header
headers={"Authorization": "Bearer TOKEN"},
timeout=10,
)
print(r.json()["json"]) # {'name': 'Asha', 'plan': 'pro'}
# Error handling that distinguishes failure modes
try:
r = requests.get("https://api.example.com/health", timeout=5)
r.raise_for_status()
except requests.Timeout:
print("service too slow")
except requests.HTTPError as e:
print("bad status:", e.response.status_code)
except requests.ConnectionError:
print("network/DNS problem")Sessions, Retries & httpx/async
A Session reuses TCP connections (much faster for many calls) and carries default headers. httpx mirrors the API and adds async — the natural pair for FastAPI services.
import requests
from requests.adapters import HTTPAdapter, Retry
session = requests.Session()
session.headers.update({"Authorization": "Bearer TOKEN"})
# Automatic retries with backoff for flaky upstreams
retries = Retry(total=3, backoff_factor=0.5,
status_forcelist=[502, 503, 504])
session.mount("https://", HTTPAdapter(max_retries=retries))
for page in range(1, 4): # pooled connections
r = session.get("https://api.example.com/items",
params={"page": page}, timeout=10)
# httpx — same feel, plus async (used inside FastAPI)
# import httpx, asyncio
# async def fetch_all(urls):
# async with httpx.AsyncClient(timeout=10) as client:
# responses = await asyncio.gather(*(client.get(u) for u in urls))
# return [r.json() for r in responses]
# ^ 20 API calls in the time of the slowest one — not the sumKey Points to Remember
- 1ALWAYS pass timeout= — the default waits forever and hangs services
- 2raise_for_status() converts 4xx/5xx into catchable HTTPError
- 3json= to send, .json() to receive; params= builds query strings safely
- 4Session = pooling + shared headers + retry mounting; httpx = same API + async
Interview Questions
Sign in to ask AriaWhat happens if you skip timeout on requests.get in a web service?
Difference between data= and json= in requests.post?
When would you pick httpx over requests?
Ask Aria about requests & httpx — Calling APIs
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.