Aller au contenu
English

Les bases de HTTP

  • Leçon 2
  • 35 min
  • Module 1 : Comprendre la requête Web

Ce que vous saurez faire

Lisez toute requête et réponse HTTP, partie par partie. Choisissez la bonne méthode et le bon code d’état pour votre API. Chaque point de terminaison que vous créez dans ce cours repose sur un choix de ces parties.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 35 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

  • Un terminal avec un environnement virtuel Python contenant httpx 0.28.1. Par exemple, votre projet ticket-cleaner, configuré dans Isoler les dépendances : exercices guidés : configurer ticket-cleaner. Si vous n’en avez pas, créez-en un dans un nouveau dossier : python3 -m venv .venv. Activez-le, puis exécutez python -m pip install httpx==0.28.1.
  • Une connexion Internet. Les exemples utilisent Postman Echo, un service public gratuit de Postman qui vous renvoie votre requête. Aucun compte n’est nécessaire.

Testé avec Python 3.14.6 et httpx 0.28.1 sur macOS.

Voici la requête que vous enverrez à votre API plus tard dans le cours. Elle est présentée en texte, exactement comme HTTP l’envoie :

An HTTP request
POST /v1/classify?lang=en HTTP/1.1
Host: api.example.com
Content-Type: application/json
Accept: application/json
X-API-Key: k-7f3a9c
{"subject": "Charged twice for March", "body": "Same invoice two times."}
Partie Dans l’exemple Signification
Méthode POST Ce que le client veut faire.
Chemin et paramètres de requête /v1/classify?lang=en La ressource visée, avec des valeurs supplémentaires.
En-têtes Content-Type: application/json et les lignes suivantes Des renseignements sur la requête, sous forme de lignes Name: value (nom : valeur).
Ligne vide Marque la fin des en-têtes.
Corps Le texte JSON Les données que le client envoie. Facultatif.

La méthode indique ce que le client veut faire avec la ressource. Les API en utilisent surtout cinq :

Méthode Signification Corps? Exemple
GET Lire une ressource. Ne rien changer. Non GET /v1/categories
POST Envoyer des données à traiter ou créer une ressource. Oui POST /v1/classify
PUT Remplacer complètement une ressource. Oui PUT /v1/tickets/T-1001
PATCH Modifier une partie d’une ressource. Oui PATCH /v1/tickets/T-1001
DELETE Supprimer une ressource. Non DELETE /v1/tickets/T-1001

GET est sûre : elle ne change jamais rien sur le serveur. Un client, un navigateur ou un cache peut donc la répéter sans risque. C’est pourquoi une requête qui modifie des données ne doit jamais utiliser GET. Un navigateur peut charger un lien GET avant que vous cliquiez dessus. Ce lien ne doit rien supprimer.

Une API organisée autour de ressources et de ces méthodes s’appelle une API REST. Les ressources sont des éléments avec une adresse, comme /v1/tickets/T-1001. La plupart des API Web suivent ce style, tout comme l’API de ce cours.

Une valeur dans l’URL peut se trouver dans le chemin ou dans les paramètres de requête. Ces deux emplacements ont des rôles différents :

Type Exemple Utilisation
Paramètre de chemin /v1/tickets/T-1001 Indiquer la ressource visée. Sans ce paramètre, l’URL désigne autre chose.
Paramètre de requête /v1/tickets?status=open&limit=20 Préciser des options : filtres, ordre de tri, taille de page. On peut généralement les omettre.

Toutes les valeurs d’une URL sont du texte. Le serveur convertit limit=20 en nombre 20. Il doit rejeter limit=twenty avec une erreur claire, comme vous l’avez fait pour les données de fichiers dans le cours Python.

Les en-têtes transmettent des renseignements sur la requête ou la réponse. Leur nom ne distingue pas les majuscules des minuscules : content-type et Content-Type désignent le même en-tête. Voici les en-têtes courants dans ce cours :

En-tête Envoyé par Signification
Content-Type Les deux Le format du corps, par exemple application/json.
Accept Client Les formats que le client peut lire.
X-API-Key ou Authorization Client Prouve l’identité de l’appelant. Le module 6 ajoute une clé d’API.
X-Request-ID Serveur Un identifiant de cette requête, pour la retrouver dans les journaux (logs). Le module 6 l’ajoute.
Content-Length Les deux La taille du corps en octets.

Les en-têtes qui commencent par X- ne font pas partie de la norme HTTP. Les applications les définissent pour leurs propres besoins.

Un corps peut contenir n’importe quelles données, mais les API utilisent presque toujours JSON (JavaScript Object Notation). JSON est du texte contenant des objets, des listes, des chaînes, des nombres, true (vrai), false (faux) et null (nul). Vous l’avez utilisé dans le cours Python. L’en-tête Content-Type: application/json indique à l’autre côté comment lire le corps. Sans lui, plusieurs serveurs rejettent le corps ou le lisent comme du texte brut.

Amira utilise Postman Echo, qui répond avec une copie de ce qu’il a reçu. Elle démarre Python en mode interactif dans son environnement virtuel (python). Elle envoie ensuite une requête GET avec deux paramètres de requête :

Interactive Python
>>> import httpx
>>> r = httpx.get("https://postman-echo.com/get", params={"status": "open", "limit": 2}, timeout=10)
>>> r.request.url
URL('https://postman-echo.com/get?status=open&limit=2')
>>> r.status_code, r.headers["content-type"]
(200, 'application/json; charset=utf-8')
>>> r.json()["args"]
{'status': 'open', 'limit': '2'}

httpx a construit les paramètres de requête à partir du dictionnaire : ?status=open&limit=2. Le serveur a reçu limit comme texte '2', et non comme nombre 2. Toutes les valeurs d’une URL sont du texte.

Elle envoie ensuite une requête POST avec un corps JSON :

Interactive Python
>>> r = httpx.post("https://postman-echo.com/post", json={"subject": "Charged twice", "priority": 1}, timeout=10)
>>> r.request.headers["content-type"]
'application/json'
>>> r.request.content
b'{"subject":"Charged twice","priority":1}'
>>> r.json()["json"]
{'subject': 'Charged twice', 'priority': 1}

L’argument json= a fait deux choses. Il a converti le dictionnaire en texte JSON pour le corps et ajouté l’en-tête Content-Type: application/json. Dans le corps, priority reste un nombre, car JSON prend en charge les nombres.

Le code d’état indique le résultat au client. Vous avez vu les groupes dans le cours Python : 2xx pour un succès, 4xx pour un problème avec la requête. Le groupe 5xx indique un problème sur le serveur. Une API doit choisir le code le plus précis, car les programmes agissent en fonction de ce code :

Code Nom Quand l’utiliser
200 OK (succès) La requête a réussi et le corps contient le résultat.
201 Created (créé) Une requête POST a créé une ressource.
204 No Content (aucun contenu) L’opération a réussi et il n’y a rien à renvoyer.
400 Bad Request (requête incorrecte) La requête est incorrecte de façon générale.
401 Unauthorized (non authentifié) Aucune information d’authentification valide, par exemple une clé d’API manquante.
403 Forbidden (interdit) Les informations d’authentification sont valides, mais l’action n’est pas permise.
404 Not Found (introuvable) Aucune ressource à ce chemin.
413 Content Too Large (contenu trop volumineux) Le corps dépasse la taille acceptée par le serveur.
422 Unprocessable Content (contenu impossible à traiter) Le JSON est lisible, mais une valeur n’est pas valide. FastAPI l’utilise pour les erreurs de validation.
429 Too Many Requests (trop de requêtes) Le client a envoyé trop de requêtes. Attendez, puis réessayez.
500 Internal Server Error (erreur interne du serveur) Le serveur a rencontré une erreur inattendue : un bogue.
503 Service Unavailable (service indisponible) Le serveur, ou un composant nécessaire, est indisponible pour le moment. Réessayez plus tard.

La différence entre 4xx et 5xx détermine ce que le client fait ensuite. Après un 4xx, le client doit modifier la requête : la renvoyer ne sert à rien. Après un 503, la même requête peut réussir plus tard.

  1. Démarrez Python en mode interactif dans un environnement virtuel contenant httpx.

  2. Envoyez une requête GET à https://postman-echo.com/get avec les paramètres de requête category=billing et page=3. Affichez r.request.url et r.json()["args"].

    Vous voyez ?category=billing&page=3 dans l’URL, et les deux valeurs sous forme de texte.

  3. Envoyez une requête POST à https://postman-echo.com/post avec le corps JSON {"subject": "Locked out", "urgent": true}. Affichez r.json()["json"].

    Le corps revient avec 'urgent': True : le true de JSON est devenu True en Python.

  4. Envoyez une requête qui reçoit le code d’état de votre choix. Postman Echo répond à https://postman-echo.com/status/404 avec le code 404. Affichez r.status_code, puis essayez 201 et 503.

Le service de soutien veut trois fonctionnalités de plus. Pour chacune, écrivez la méthode, le chemin, les paramètres de requête éventuels et le code d’état en cas de succès. Précisez aussi s’il y a un corps. Utilisez /v1/tickets comme chemin de base.

  1. Obtenir les billets de soutien ouverts, 20 à la fois.
  2. Changer seulement l’état du billet T-1042 pour closed (fermé).
  3. Supprimer le billet T-1042. Après cela, que renvoie une requête GET pour ce même billet?
Afficher une réponse possible
  1. GET /v1/tickets?status=open&limit=20. Aucun corps. 200, avec une liste dans le corps. Le filtre et la taille de page sont des options, donc des paramètres de requête.
  2. PATCH /v1/tickets/T-1042, avec le corps {"status": "closed"}. 200 avec le billet modifié, ou 204 sans corps. L’identifiant est dans le chemin, car il indique la ressource visée.
  3. DELETE /v1/tickets/T-1042. Aucun corps. 204. Une requête ultérieure GET /v1/tickets/T-1042 renvoie 404, car la ressource n’existe plus.

Erreur courante

Le serveur ignore le corps JSON

Symptôme : vous envoyez du JSON correct, mais le serveur répond 422 et indique que le corps n’est pas valide. L’API de ce cours répond "fields": ["body"] (champs : corps). Certains services, comme Postman Echo, devinent le format. La même requête peut donc y réussir et échouer sur votre API.

Cause : la requête n’a pas d’en-tête Content-Type: application/json. Le serveur ne sait donc pas que le corps est du JSON. Cela arrive quand vous écrivez vous-même le corps en texte, par exemple httpx.post(url, content='{"subject": "x"}'). Cela arrive aussi dans curl sans option -H.

Solution :

  1. Dans httpx, utilisez json= avec un dictionnaire. Il définit l’en-tête pour vous.
  2. Si vous envoyez le corps en texte, ajoutez vous-même l’en-tête : headers={"Content-Type": "application/json"}.
  3. Vérifiez la requête réellement envoyée : r.request.headers.

Vérifiez votre compréhension

Un point de terminaison GET /v1/tickets/delete?id=T-1042 supprime un billet. Quel est le problème avec cette conception?

Afficher la réponse

Il utilise GET pour modifier des données. GET doit être sûre : les navigateurs, les aperçus de liens et les caches envoient des requêtes GET sans consulter l’utilisateur. Chacune de ces requêtes supprimerait un billet. Utilisez DELETE /v1/tickets/T-1042. C’est la méthode qui indique l’action, pas un mot dans le chemin.

Vérifiez votre compréhension

Votre API ne peut pas joindre le classificateur dont elle dépend. Quel code d'état doit-elle renvoyer : 400, 404, 500 ou 503? Pourquoi?

Afficher la réponse

503 Service Unavailable (service indisponible). La requête est correcte (ni 400 ni 404), et le serveur n’a pas de bogue (pas 500). Un composant nécessaire au service est indisponible pour le moment, et la même requête peut réussir plus tard. Un client peut réessayer sans risque après une courte attente.

Récapitulatif

  • Une requête comprend une méthode, un chemin avec des paramètres de requête facultatifs, des en-têtes et un corps facultatif. Une réponse comprend un code d’état, des en-têtes et un corps.
  • GET lit et est sûre. POST, PUT, PATCH et DELETE modifient des données.
  • Un paramètre de chemin indique la ressource visée. Un paramètre de requête donne une option. Toutes les valeurs d’une URL sont du texte.
  • Content-Type: application/json indique à l’autre côté que le corps est du JSON.
  • Choisissez le code d’état le plus précis. 4xx : modifiez la requête. 5xx : le problème est sur le serveur.

Ensuite, vous examinerez de vraies requêtes avec les outils de développement de votre navigateur et avec curl.

Leçon suivante : Examiner une requête