Derrière chaque chatbot, chaque agent IA, chaque dashboard, il y a une réalité moins glamour : des requêtes HTTP. Pour parler à une API REST, il faut un client propre. Pendant quinze ans, la bibliothèque Requests a été la réponse évidente. Mais le monde a bougé : asyncio, HTTP/2, timeouts stricts, connexions réutilisées. C'est exactement ce que propose httpx, avec une syntaxe quasi identique à Requests. Tu ne repars pas de zéro, tu montes en gamme.
Aujourd'hui, on interroge une vraie API publique (sans clé, sans inscription) puis on termine en branchant un modèle de langage. Tout le code tourne tel quel sur ta machine.
Étape 1 : installer httpx
Un environnement virtuel, un pip install, et c'est réglé. Pas de dépendance exotique, httpx s'installe en une seconde.
python -m venv venv
source venv/bin/activate # sous Windows : venv\Scripts\activate
pip install httpxÉtape 2 : ton premier GET
On commence par le grand classique : récupérer une ressource. Ici on tape dans JSONPlaceholder, une fausse API de démo gratuite et fiable, parfaite pour tester sans clé ni inscription.
import httpx
r = httpx.get("https://jsonplaceholder.typicode.com/posts/1")
print(r.status_code) # 200
print(r.json()["title"])Deux lignes suffisent. r.json() convertit la réponse JSON en dictionnaire Python. Si l'API renvoie du texte brut, utilise r.text ; pour du binaire comme une image, c'est r.content.
Étape 3 : paramètres, en-têtes et timeouts
Une vraie requête, c'est rarement une simple URL. On ajoute des paramètres de requête, des en-têtes et, surtout, un timeout. Sans timeout, ton script peut rester bloqué une éternité sur une API qui rame.
r = httpx.get(
"https://jsonplaceholder.typicode.com/comments",
params={"postId": 1},
headers={"User-Agent": "mon-script/1.0"},
timeout=10.0,
)
comments = r.json()
print(len(comments), "commentaires") # 5Le paramètre params gère l'encodage de l'URL à ta place. Le timeout de dix secondes vaut pour l'ensemble de la requête, pas seulement la connexion.
Étape 4 : envoyer des données avec POST
Pour créer une ressource, on passe au POST avec un corps JSON. httpx s'occupe de sérialiser ton dictionnaire et de poser le bon en-tête Content-Type.
payload = {
"title": "Mon article",
"body": "Contenu du post",
"userId": 1,
}
r = httpx.post("https://jsonplaceholder.typicode.com/posts", json=payload)
print(r.status_code) # 201 Created
print(r.json()["id"]) # 101Étape 5 : gérer les erreurs sans crasher
Une API peut être lente, indisponible, ou renvoyer une 404. Ton script doit survivre. httpx lève des exceptions précises selon le type de problème, à toi de les attraper.
try:
r = httpx.get("https://jsonplaceholder.typicode.com/posts/99999", timeout=5.0)
r.raise_for_status() # lève une exception si le code est >= 400
data = r.json()
except httpx.TimeoutException:
print("L'API ne répond pas : timeout.")
except httpx.HTTPStatusError as e:
print(f"Erreur HTTP {e.response.status_code}")
except httpx.RequestError as e:
print(f"Problème réseau : {e}")raise_for_status() transforme un code d'erreur HTTP en exception. Les deux autres except attrapent les soucis de transport, comme un serveur injoignable ou une connexion coupée.
Étape 6 : un client réutilisable
Enchaîner des dizaines de httpx.get() rouvre une connexion à chaque fois. httpx.Client garde le canal ouvert et centralise tes réglages : adresse de base, timeout, en-têtes communs.
with httpx.Client(
base_url="https://jsonplaceholder.typicode.com",
timeout=10.0,
) as client:
user = client.get("/users/1").json()
posts = client.get("/posts", params={"userId": user["id"]}).json()
print(user["name"], "a écrit", len(posts), "posts")Le with ferme proprement la connexion. base_url évite de répéter l'adresse complète à chaque appel : tu ne passes plus que le chemin.
Étape 7 : bonus, passer en asynchrone
Si tu interroges plusieurs APIs en parallèle, l'async divise le temps d'attente. httpx.AsyncClient se marie naturellement avec asyncio.
import asyncio
async def main():
async with httpx.AsyncClient(timeout=10.0) as client:
urls = [f"https://jsonplaceholder.typicode.com/posts/{i}" for i in range(1, 6)]
reponses = await asyncio.gather(*(client.get(u) for u in urls))
for r in reponses:
print(r.json()["title"])
asyncio.run(main())Étape 8 : interroger une API d'IA
Tout ce qu'on vient d'apprendre s'applique directement aux modèles. Voici l'appel minimal à l'API d'OpenAI, sans SDK, juste avec httpx.
client = httpx.Client(
base_url="https://api.openai.com/v1",
headers={"Authorization": "Bearer VOTRE_CLE"},
timeout=30.0,
)
r = client.post("/chat/completions", json={
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "Explique le théorème de Pythagore en une phrase."}],
})
print(r.json()["choices"][0]["message"]["content"])Remplace VOTRE_CLE par ta clé. Le même schéma fonctionne avec Mistral, Anthropic ou n'importe quel fournisseur compatible OpenAI : tu changes l'URL, les en-têtes et le corps, pas ta logique.
Conclusion
httpx ne réinvente pas la roue : il reprend la simplicité de Requests et y ajoute ce qu'il faut pour le Python moderne. Timeouts partout, connexions réutilisées, async natif. Une fois ce réflexe pris, interroger une API ne te fera plus jamais peur. Prochaine étape logique : emballer tes appels dans une commande propre avec Typer, ou valider les réponses avec Pydantic. Le trio httpx + Pydantic + Typer, c'est la base d'un outil Python sérieux.






