httpx
Le client HTTP moderne pour Python : même API que la lib historique
requests, mais avec en bonus le support
async, le HTTP/2, et l'intégration native dans
l'écosystème FastAPI. Le choix par défaut pour parler à une API
externe depuis du code Python en 2026.
À quoi ça sert
Dès que ton code Python doit parler à une autre API
(météo, GitHub, OpenAI, ton propre backend depuis ton frontend Python…),
il te faut un client HTTP. Python a une lib standard
(urllib) mais elle est verbeuse — la communauté utilise
depuis 15 ans requests, et depuis 2020 son successeur
moderne : httpx.
- API synchrone style requests — drop-in remplaçant
pour
requests.get(...). - API async — la vraie raison d'utiliser httpx. Indispensable dans une app FastAPI ou pour des appels parallèles.
- HTTP/2 — plus rapide pour multiplexer plusieurs requêtes sur la même connexion.
- Test client pour FastAPI —
TestClientde FastAPI est basé sur httpx, donc apprendre httpx te sert deux fois.
urllib = stdlib Python, verbeux, à éviter sauf contrainte « zéro dépendance ». requests = lib historique (2011), API très lisible mais maintenance ralentie et pas d'async. httpx = même API que requests + async + HTTP/2 + typage. Pour un nouveau projet, prends httpx. Sur un vieux projet, requests reste très bien — le code se traduit ligne à ligne.
Un exemple d'usage
Tu veux récupérer la météo actuelle d'une ville depuis l'API publique open-meteo.com :
import httpx
response = httpx.get(
"https://api.open-meteo.com/v1/forecast",
params={
"latitude": 50.85,
"longitude": 4.35,
"current": "temperature_2m",
},
timeout=10.0,
)
response.raise_for_status() # exception si 4xx/5xx
data = response.json()
print(data["current"]["temperature_2m"]) # 12.3
Le code se lit comme du pseudo-code : URL, paramètres, timeout. On
appelle raise_for_status() pour transformer un code
HTTP d'erreur en exception explicite, puis .json() pour
parser le corps de la réponse.
How-to : installer et utiliser httpx
-
Installer httpx
Avec UV :
bashuv add httpxPour activer HTTP/2 (optionnel), il faut un extra :
bashuv add "httpx[http2]" -
Les méthodes HTTP de base
pythonimport httpx # GET (avec query parameters) r = httpx.get("https://api.example.com/users", params={"page": 2}) # POST (avec corps JSON) r = httpx.post("https://api.example.com/users", json={"name": "Alice", "age": 30}) # PUT / PATCH / DELETE — même signature httpx.put(url, json=...) httpx.patch(url, json=...) httpx.delete(url) -
Inspecter la réponse
pythonr.status_code # 200, 404, 500… r.headers # dict des en-têtes de réponse r.text # corps en str r.content # corps en bytes (binaire) r.json() # parse en dict/list r.url # URL finale (après redirects) r.raise_for_status() # exception si 4xx/5xx -
Headers, auth, timeouts
python# Headers personnalisés (ex: token API) r = httpx.get( url, headers={"Authorization": f"Bearer {token}", "User-Agent": "mon-app/1.0"}, ) # Auth basique r = httpx.get(url, auth=("user", "password")) # Timeout r = httpx.get(url, timeout=10.0) r = httpx.get(url, timeout=httpx.Timeout( connect=5.0, read=30.0, write=10.0, pool=5.0, ))Toujours mettre un timeoutSans
timeout, une requête peut bloquer ton code indéfiniment si le serveur tarde à répondre. C'est particulièrement critique dans une API FastAPI : un appel sortant sans timeout peut pendre toutes tes requêtes entrantes. httpx met un timeout par défaut de 5s (contrairement à requests qui n'en met pas) — bonne pratique conservée. -
Utiliser un Client pour plusieurs requêtes
Si tu fais plus d'une requête vers le même hôte, utilise un
Client: il réutilise la connexion TCP (plus rapide) et factorise la config.pythonwith httpx.Client( base_url="https://api.github.com", headers={"Authorization": f"Bearer {token}"}, timeout=10.0, ) as client: user = client.get("/user").json() repos = client.get("/user/repos").json() issues = client.get("/issues").json() -
Async pour les requêtes en parallèle
C'est la raison d'utiliser httpx plutôt que requests.
AsyncClientpermet de lancer N requêtes simultanément sans bloquer le thread.pythonimport asyncio import httpx async def fetch_all(urls): async with httpx.AsyncClient(timeout=10) as client: tasks = [client.get(u) for u in urls] responses = await asyncio.gather(*tasks) return [r.json() for r in responses] urls = ["https://api.x.com/a", "https://api.x.com/b", "…"] results = asyncio.run(fetch_all(urls))10 requêtes séquentielles à 200 ms = 2 s. Les mêmes 10 en async avec
gather= ~200 ms total. Différence massive sur un appel-aggregator (style « passerelle » qui interroge plusieurs services). -
Upload de fichier et download streamé
python# Upload (multipart/form-data) with open("photo.jpg", "rb") as f: r = httpx.post(url, files={"image": f}) # Download streamé (pour gros fichiers, sans tout mettre en RAM) with httpx.stream("GET", big_url) as r: with open("out.zip", "wb") as f: for chunk in r.iter_bytes(): f.write(chunk)
Aide-mémoire
import httpx
r = httpx.get(url, params={"q": "…"}, timeout=10)
r.raise_for_status(); r.json()
httpx.post(url, json={...})
httpx.put(url, json={...}); httpx.delete(url)
with httpx.Client(base_url="…", timeout=10) as c:
c.get("/a"); c.post("/b", json=...)
async with httpx.AsyncClient() as c:
r = await c.get(url)
results = await asyncio.gather(*tasks)
r.status_code; r.headers; r.text; r.content
r.json(); r.raise_for_status()
httpx et le reste de l'écosystème
-
FastAPI — couple
évident. FastAPI est un serveur asynchrone ; depuis du
code FastAPI on parle aux autres APIs avec
AsyncClientpour ne pas bloquer le worker. LeTestClientde FastAPI est lui-même un wrapper httpx. -
Pydantic — pattern
habituel :
data = MyModel.model_validate(response.json()). Tu transformes une réponse JSON en objet typé d'un coup. -
pytest — le module
respxmocke httpx pour les tests, sans toucher au réseau. Tests rapides et déterministes. - BeautifulSoup — scraping = récupérer le HTML avec httpx, le parser avec BeautifulSoup. Remplace progressivement le couple requests + BeautifulSoup.
- Hugging Face / Ollama — pour appeler les endpoints HTTP de ces services depuis Python (inférence à distance d'un modèle).
-
Loguru /
logging — en cas
d'erreur, logger
r.status_codeetr.textrend le debug bien plus rapide qu'une simpleHTTPStatusError.
La majorité du code traduit ligne-à-ligne :
requests.get(...) → httpx.get(...),
même API pour params, json,
headers, auth. Les rares différences :
timeout par défaut (httpx en met un, requests non),
Session → Client, et le support async
en bonus.
Pour aller plus loin
- Site officiel : python-httpx.org
- Quickstart : python-httpx.org/quickstart
- Async client : python-httpx.org/async
- respx (mock httpx pour pytest) : lundberg.github.io/respx