Cheatsheets — vue longue
retour à la listeToutes les pages concaténées sur un seul document, pour un Ctrl-F direct.
curl
page dédiée →Les flags qui couvrent 90 % des cas
| Flag | Effet |
|---|---|
-X POST |
méthode (inutile avec -d, qui implique POST) |
-H "K: V" |
un header, répétable |
-d '{"a":1}' |
corps de la requête |
-G |
envoie les -d en query string au lieu du corps |
--data-urlencode "q=a b" |
encode la valeur |
-s |
silencieux, pas de barre de progression |
-S |
affiche quand même les erreurs (à coupler avec -s) |
-i |
inclut les headers de réponse |
-I |
headers seulement, requête HEAD |
-L |
suit les redirections |
-o fichier |
écrit dans un fichier |
-O |
garde le nom distant |
-u user:pass |
authentification basique |
--max-time 30 |
timeout global |
-w '%{http_code}' |
formate une sortie après coup |
POST JSON, le cas de référence
curl -sS -X POST "https://api.example.com/v1/sessions" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"agent_id": "a_123", "task": "trouver le produit"}'
{"id":"s_88fe21","status":"queued","created_at":"2026-08-07T14:12:03Z"}
Sans Content-Type: application/json, beaucoup d'API répondent 415 Unsupported Media Type. C'est l'oubli le plus fréquent.
Corps trop long pour la ligne de commande : -d @payload.json lit un fichier.
GET avec des paramètres
curl -sS -G "https://api.example.com/v1/items" \
--data-urlencode "q=chaussure noire" \
--data-urlencode "page=2"
-G évite d'encoder soi-même les espaces et les accents.
Lire la réponse
curl -s https://api.github.com/repos/astral-sh/uv | jq '.stargazers_count, .license.name'
62841
"Apache License 2.0"
curl -s https://api.example.com/items | jq '.items[] | {id, name}'
curl -s https://api.example.com/items | jq -r '.items[].name' # -r : sans guillemets
Debug
curl -i https://example.com # headers + corps
curl -I https://example.com # headers seuls
curl -v https://example.com # tout le dialogue, TLS compris
curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" https://example.com
200 0.184s
-w sert à mesurer sans polluer la sortie. Autres variables utiles :
%{size_download}, %{redirect_url}, %{content_type}.
Fichiers
curl -O https://example.com/data.csv # garde le nom
curl -o local.csv https://example.com/data.csv
curl -L -o file.zip https://example.com/dl # suit la redirection
curl -F "file=@photo.jpg" -F "note=test" https://api.example.com/upload
-F fait du multipart, -d fait du form-urlencoded ou du brut : ce ne sont pas les mêmes
requêtes.
Le pipe vers bash
curl -LsSf https://astral.sh/uv/install.sh | sh
Correct pour un installeur officiel. Pour tout le reste, lire d'abord :
curl -sSL https://exemple.com/install.sh | less
Équivalences avec Python
| curl | requests |
|---|---|
-X POST |
requests.post(...) |
-H "K: V" |
headers={"K": "V"} |
-d '{"a":1}' |
json={"a": 1} |
-G --data-urlencode "q=x" |
params={"q": "x"} |
-u user:pass |
auth=("user", "pass") |
--max-time 30 |
timeout=30 |
-L |
allow_redirects=True (défaut) |
Astuce navigateur : dans l'onglet Réseau des DevTools, clic droit sur une requête puis « Copy as cURL » reproduit l'appel complet, cookies et headers inclus.
See also
Python requests
page dédiée →Client HTTP synchrone. Pas de timeout par défaut — toujours le passer explicitement.
Le squelette à écrire de mémoire
import os
import requests
BASE = "https://api.example.com/v1"
r = requests.post(
f"{BASE}/environments",
headers={
"Authorization": f"Bearer {os.environ['API_KEY']}",
"Content-Type": "application/json",
},
json={"name": "demo", "url": "https://example.com"},
timeout=30,
)
r.raise_for_status()
print(r.status_code, r.json())
json= sérialise le dict et pose Content-Type: application/json tout seul. data= envoie
du form-urlencoded ou des bytes bruts — c'est la confusion la plus fréquente.
Réponse
| Attribut | Contenu |
|---|---|
r.status_code |
entier, 200, 404… |
r.ok |
True si status_code < 400 |
r.json() |
corps parsé, lève JSONDecodeError si ce n'est pas du JSON |
r.text |
corps brut décodé |
r.headers |
dict insensible à la casse |
r.raise_for_status() |
lève HTTPError sur 4xx/5xx, ne fait rien sinon |
Session : réutiliser la connexion et les headers
with requests.Session() as s:
s.headers.update({"Authorization": f"Bearer {os.environ['API_KEY']}"})
for page in range(1, 6):
r = s.get(f"{BASE}/items", params={"page": page}, timeout=30)
r.raise_for_status()
print(r.json()["items"])
params= construit la query string, pas besoin de la concaténer à la main.
Polling d'un job asynchrone
import time
def wait_for(session_id: str, timeout_s: int = 300, every_s: int = 3) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
r = requests.get(f"{BASE}/sessions/{session_id}", timeout=30)
r.raise_for_status()
payload = r.json()
if payload["status"] in {"completed", "failed"}:
return payload
time.sleep(every_s)
raise TimeoutError(f"session {session_id} toujours en cours après {timeout_s}s")
Erreurs à distinguer
try:
r = requests.get(url, timeout=10)
r.raise_for_status()
except requests.Timeout: # dépassement du timeout
...
except requests.ConnectionError: # DNS, refus de connexion, réseau
...
except requests.HTTPError as exc: # 4xx / 5xx après raise_for_status
print(exc.response.status_code, exc.response.text[:200])
Toutes héritent de requests.RequestException.
Charger la clé depuis un .env
from dotenv import load_dotenv # pip install python-dotenv
load_dotenv()
key = os.environ["API_KEY"] # KeyError explicite si absente
os.environ["X"] lève si la variable manque, os.getenv("X") renvoie None en silence.
Préférer le premier pour une clé obligatoire.
Debug rapide
print(r.request.method, r.request.url)
print(r.request.headers)
print(r.request.body)
Équivalences avec curl
| curl | requests |
|---|---|
-X POST |
requests.post(...) |
-H "K: V" |
headers={"K": "V"} |
-d '{"a":1}' |
json={"a": 1} |
-G --data-urlencode "q=x" |
params={"q": "x"} |
-u user:pass |
auth=("user", "pass") |
--max-time 30 |
timeout=30 |
See also
- httpx — même API, plus l'async et un timeout par défaut