Lire une réponse

Les codes de statut, les en-têtes de réponse et le corps.

Chaque requête reçoit exactement une réponse (sauf si la connexion coupe, ce qui est une autre forme de réponse traitée dans une leçon plus loin). Une réponse a trois parties : une ligne de statut, des en-têtes et un corps. Quand on débute dans le test, on a tendance à ne regarder que le corps, parce que c’est là que sont les données. La plupart des bugs qui passent à travers se trouvent dans les deux autres parties.

À quoi ressemble une réponse

Comme la requête, une réponse HTTP/1.1 est du texte brut. Voici la réponse à GET /api/health, telle que curl l’affiche avec l’option -i (qui imprime les en-têtes avec le corps). Quelques en-têtes d’infrastructure ont été retirés.

Réponse brute
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
x-powered-by: TestingAPIs

{"status":"healthy","uptimeSeconds":3542,"timestamp":"2026-09-30T18:28:12Z"}

La première ligne est la ligne de statut : la version du protocole, un code de statut à trois chiffres et une courte phrase explicative. Viennent ensuite les en-têtes, un par ligne, puis une ligne vide, puis le corps. La phrase explicative n’est là que pour les humains. Les clients et les tests doivent regarder le nombre. HTTP/2 supprime complètement la phrase, donc un test qui vérifie le texte "OK" peut casser quand le serveur est mis à jour.

Les classes de codes de statut

Le premier chiffre du code de statut indique la classe de la réponse. On peut souvent juger un résultat à ce seul chiffre.

ClasseSignificationÀ qui la faute
1xxInformation. La requête est toujours en cours.Personne. Vous les voyez rarement directement.
2xxSuccès. Le serveur a fait ce que vous demandiez.Personne.
3xxRedirection. Allez voir ailleurs.Personne. Le client doit donner suite.
4xxErreur du client. La requête était fausse.Le client : mauvaise saisie, pas de droits, mauvaise URL.
5xxErreur du serveur. La requête était peut-être correcte.Le serveur, ou quelque chose derrière lui.

Cette dernière colonne explique pourquoi les codes de statut comptent tant dans le test. Un 4xx dit "corrigez votre requête". Un 5xx dit "quelque chose a cassé chez nous". Si vous envoyez n’importe quoi et recevez un 500, c’est un bug même si la requête était mauvaise, car le serveur a planté là où il aurait dû refuser poliment la saisie avec un 400. Trouver ces 500 est l’une des choses les plus utiles que l’on puisse faire quand on débute.

Les codes que vous verrez le plus

CodeNomUsage typique
200OKLa requête a marché et le corps contient le résultat.
201CreatedUn POST a créé un nouvel enregistrement.
204No ContentÇa a marché et il n’y a volontairement pas de corps. Courant après un DELETE.
301 / 302Moved Permanently / FoundLa ressource est à l’URL de l’en-tête Location.
304Not ModifiedVotre copie en cache est toujours à jour. Vu avec le cache.
400Bad RequestLa requête est mal formée ou une valeur est invalide.
401UnauthorizedPas d’identifiants, ou des identifiants faux. Malgré le nom, cela veut dire non authentifié.
403ForbiddenLes identifiants sont bons, mais cet utilisateur n’a pas le droit de faire ça.
404Not FoundRien à cette URL, ou aucun enregistrement avec cet ID.
405Method Not AllowedL’URL existe, mais pas avec cette méthode.
409ConflictLa requête entre en conflit avec l’état actuel, comme un e-mail en double.
422Unprocessable ContentLa syntaxe est bonne mais les données enfreignent une règle.
429Too Many RequestsVous avez atteint une limite de débit. Ralentissez.
500Internal Server ErrorUne erreur non gérée sur le serveur.
502Bad GatewayUn proxy a reçu une mauvaise réponse du serveur derrière lui.
503Service UnavailableLe serveur est surchargé ou en maintenance.

Les API ne sont pas d’accord sur certains d’entre eux. Une équipe renvoie 400 pour toutes les erreurs de validation, une autre utilise 422. Certaines renvoient 200 pour une suppression avec un message dans le corps, d’autres 204 sans rien. Aucune n’a tort. Ce que vous vérifiez, c’est que l’API respecte sa propre documentation et reste cohérente d’un point d’accès à l’autre.

Essayer des codes de statut

/api/status/{code} répond avec le code que vous mettez dans le chemin. C’est utile pour voir comment un outil ou une bibliothèque cliente se comporte face à un statut donné. Essayez-en quelques-uns :

GET/api/status/201
GET/api/status/503

Depuis curl, le 503 ressemble à ceci :

Réponse
HTTP/1.1 503 Service Unavailable
Content-Type: application/json; charset=utf-8
retry-after: 5

{
  "status": 503,
  "statusText": "Service Unavailable",
  "category": "server-error",
  "message": "This is a 503 response. Use /api/status/{code} to request any status."
}

Remarquez l’en-tête retry-after: 5. Un 503 ou un 429 indique souvent au client combien de secondes attendre avant de réessayer, et un client bien élevé le respecte. Vous vérifiez la présence de l’en-tête, pas seulement le statut.

Les codes hors de la plage valide sont refusés. /api/status/999 revient en 400 avec le message Status code must be between 200 and 599 (1xx cannot be sent as a final response). Et /api/status/abc renvoie un 404 avec un corps vide, parce que abc ne correspond même pas à la route. Deux mauvaises saisies, deux formes d’échec différentes. Vous verrez souvent ce schéma : une valeur du mauvais type échoue en général dans la couche de routage, avant même que le code de l’application ne s’exécute.

Les redirections

Une réponse 3xx n’a en général pas de corps utile. La partie importante est l’en-tête Location, qui dit où aller ensuite :

Réponse à GET /api/status/302
HTTP/1.1 302 Found
Content-Type: application/json; charset=utf-8
location: /api/echo

Les navigateurs et la plupart des bibliothèques HTTP suivent les redirections automatiquement et ne vous montrent que la réponse finale. C’est pratique jusqu’au jour où vous devez tester la redirection elle-même. curl ne les suit pas sauf si vous ajoutez -L, ce qui en fait le meilleur outil pour ça.

Les en-têtes de réponse

Les en-têtes de réponse décrivent le corps et donnent des instructions au client. Demandez la page 3 de la liste des produits, deux produits par page :

GET/api/Products?limit=2&page=3
En-têtes de réponse
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
x-page: 3
x-per-page: 2
x-total-count: 20
x-total-pages: 10

Content-Type indique que le corps est du JSON en UTF-8. Les quatre en-têtes x-page et x-total portent les détails de pagination : il y a 20 produits, 10 pages, et voici la page 3. Le corps n’est qu’un tableau de deux produits, donc un client qui ignore ces en-têtes n’a aucun moyen de savoir qu’il y en a d’autres. Les en-têtes qui commencent par X- sont des en-têtes personnalisés inventés par l’API. C’est l’API qui les documente, pas la norme HTTP.

Certains en-têtes contiennent des heures sous forme de timestamps Unix : le nombre de secondes depuis le 1er janvier 1970, en UTC. Les API avec limite de débit en envoient souvent un dans x-ratelimit-reset pour dire quand votre quota se renouvelle. Convertissez-le avant de vous y fier : une heure de renouvellement dans le passé, ou dans des années, est un bug que vous ne trouvez qu’en lisant les en-têtes au lieu de les sauter. (Le convertisseur de timestamp fait la conversion.)

Vous vous attendez peut-être à un en-tête Content-Length. Cette API envoie surtout Transfer-Encoding: chunked à la place, ce qui veut dire que le corps est envoyé par morceaux et que sa taille totale n’est pas annoncée d’avance. Les deux sont valides. Une réponse a l’un ou l’autre, pas les deux.

Le corps

Le corps, ce sont les données : un produit, une liste, un message d’erreur, une image. Content-Type dit comment le lire. La plupart de vos vérifications porteront sur le corps, et Lire du JSON traite cela en détail. D’abord, deux cas particuliers.

Pas de corps du tout

Un 204 signifie un succès sans corps, volontairement. La réponse n’a pas non plus de Content-Type, parce qu’il n’y a rien à décrire :

GET/api/formats/no-content
Cette requête utilise un point d’accès réservé aux membres connectés.Se connecterCréer un compte gratuit
Réponse
HTTP/1.1 204 No Content
x-powered-by: TestingAPIs

Un code client qui appelle toujours response.json() plantera ici, car une chaîne vide n’est pas du JSON valide. Si vous écrivez des helpers de test qui analysent chaque réponse, ils doivent gérer un corps vide.

Quand les en-têtes mentent

Le statut, les en-têtes et le corps sont produits par différentes parties du serveur, et rien ne les oblige à concorder. Voici une réponse qui prétend être du HTML :

GET/api/formats/wrong-content-type
Cette requête utilise un point d’accès réservé aux membres connectés.Se connecterCréer un compte gratuit
Réponse
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

{"id":1,"name":"Alice Johnson","email":"alice@example.com","roles":["admin","editor"],"active":true,"score":98.5,"manager":null}

Le corps est un JSON parfaitement valide. Une personne qui le lirait ne remarquerait jamais de problème. Un navigateur essaierait de l’afficher comme une page web, et certaines bibliothèques HTTP refuseront de l’analyser comme du JSON ou le renverront sous forme de chaîne. Ce point d’accès est cassé exprès. Dans les vrais systèmes, ce même bug vient en général d’une page d’erreur générée par un proxy ou d’un réglage par défaut du framework. Votre test doit vérifier le Content-Type explicitement.

L’inverse arrive aussi : un statut 200 avec un corps qui dit {"success": false}. Certaines API signalent toutes leurs erreurs ainsi. Les outils de supervision qui comptent les réponses 5xx ne voient jamais ces échecs, pas plus qu’un test qui ne vérifie que le code de statut. Si une API fait cela, vos tests doivent lire le corps de chaque réponse.

Ce qu’il faut vérifier sur chaque réponse

Avant de regarder un seul champ de données, confirmez les bases. Cela prend quelques secondes et attrape un nombre surprenant de bugs.

  • Le code de statut est celui que la documentation promet pour cette situation.
  • Content-Type correspond au corps que vous avez réellement reçu.
  • Les en-têtes que mentionne la documentation (pagination, Location, Retry-After) sont présents et ont du sens.
  • Le corps s’analyse et a la forme attendue.
  • Les réponses d’erreur suivent le même format que les autres erreurs de cette API.

Exercice

Pour chaque requête, notez le code de statut, le Content-Type et une phrase sur le corps.

  • /api/status/418. Cherchez pourquoi ce code existe.
  • /api/formats/emptyconnectez-vous pour voir. En quoi diffère-t-il de /api/formats/no-contentconnectez-vous pour voir ? L’un renvoie 200 et l’autre 204. Lequel, selon vous, un client gère-t-il le mieux ?
  • /api/Products?limit=2&page=99. Il n’y a pas de page 99. Quel statut et quel corps avez-vous reçus, et que disent les en-têtes de pagination ? L’auriez-vous conçu de la même façon ?
  • /api/status/list. Trouvez dans la liste un code marqué "supported": false et essayez de le demander.

S’entraîner et aller plus loin