Le code, c'est déjà une phrase
Rappel express du cours HTTP : les status codes vivent en familles. 2xx ça a marché, 3xx va voir ailleurs, 4xx c'est ta faute (client), 5xx c'est la mienne (serveur). Tu connais déjà les huit codes de base. Ici, on monte d'un cran.
Côté API, chaque réponse est une phrase complète, et le code EST le sens. Avant même de lire le JSON, ton client lit le code et sait quoi faire. Un livre ajouté au catalogue de la bibliothèque ne répond pas comme un livre déjà emprunté, qui ne répond pas comme un ISBN mal formaté. Trois situations, trois codes différents, trois phrases nettes.
Le designer d'API ne se contente pas de « ça marche / ça marche pas ». Il choisit le code juste pour chaque situation métier. C'est tout l'objet de cette leçon : apprendre à parler status couramment.
Les codes du succès qui en disent plus que 200
Tout 2xx n'est pas un 200 OK. Deux codes plus précis racontent mieux ce qui vient de se passer.
201 Created : j'ai créé, et voilà où
Quand un POST /api/livres réussit et crée une ressource, la bonne réponse n'est pas 200, c'est 201 Created. Et elle s'accompagne d'un header capital : Location, qui dit où vit la nouvelle ressource.
HTTP/1.1 201 Created
Location: /api/livres/87
Le client n'a pas à deviner l'identifiant du livre qu'il vient de créer : l'API le lui tend sur un plateau. Il peut enchaîner direct sur GET /api/livres/87. Un simple 200 sans Location, c'est dire « c'est bon » sans dire « où » : le client devra fouiller.
204 No Content : succès, rien à ajouter
204 No Content, c'est le succès muet. L'opération a réussi et il n'y a strictement rien à renvoyer dans le body. Les deux cas typiques :
- un
DELETE /api/livres/87réussi : le livre est parti, que veux-tu renvoyer de plus ? - un
PUTqui met à jour sans avoir besoin de retourner la ressource.
Le body est vide, point. Renvoyer 200 avec {} ou un message « supprimé avec succès » est moins propre : 204 dit déjà tout, dans le code lui-même.
400 contre 422 : la distinction qui sépare les pros
Voici LE point de la leçon. Côté 4xx, deux codes se ressemblent en apparence et ne disent pas du tout la même chose. Bien les distinguer, c'est rendre ton API diagnosticable.
400 Bad Request: la syntaxe est cassée. Le serveur n'arrive même pas à lire la requête. JSON malformé, accolade manquante, virgule en trop. Le message est illisible, on s'arrête à la porte.422 Unprocessable Content: la syntaxe est OK, le serveur a parfaitement lu le JSON, mais le contenu est invalide côté métier. Le titre est manquant, l'ISBN est au mauvais format, la date est dans le futur. La phrase est bien construite, mais elle dit une bêtise.
L'image simple : 400, c'est une phrase grammaticalement fausse, on n'arrive pas à la lire. 422, c'est une phrase parfaitement écrite mais fausse sur le fond. Le serveur la comprend, et la refuse.
422 est un code sûr pour toute API. Il s'appelle désormais « Unprocessable Content » (et non plus « Unprocessable Entity »). Surtout, depuis la RFC 9110 (2022), il fait partie du cœur de HTTP : il n'est plus réservé à WebDAV comme à l'époque. Tu peux l'utiliser partout, sans arrière-pensée.
409 pour le conflit, 401/403 pour l'accès
409 Conflict : l'état refuse
Parfois la requête est syntaxiquement parfaite ET valide sur le fond, mais l'état actuel des données la rend impossible. C'est 409 Conflict.
- tu veux emprunter le livre 42, mais il est déjà emprunté par quelqu'un d'autre ;
- tu crées un livre avec un ISBN qui existe déjà dans le catalogue.
Rien à reprocher à ta requête en elle-même : c'est le monde qui dit non. Ce n'est ni un 400 (la syntaxe va), ni un 422 (le contenu est valide) : c'est l'état qui bloque.
401 contre 403 : pas connecté contre pas le droit
Deux codes d'accès qu'on confond tout le temps :
401 Unauthorized: tu n'es pas authentifié. Pas de token, ou token invalide. L'API ne sait même pas qui tu es.403 Forbidden: l'API sait très bien qui tu es (token valide), mais tu n'as pas le droit. Un lecteur lambda qui tente de supprimer un livre du catalogue : il est bien connecté, mais ce n'est pas pour lui.
On creusera les tokens en leçon 7. Retiens la phrase : 401 = « je ne sais pas qui tu es », 403 = « je sais qui tu es, et c'est non ».
L'erreur qui rend une API aveugle
Le piège mortel : répondre 200 OK avec une erreur cachée dans le body. Du genre :
HTTP/1.1 200 OK
Content-Type: application/json
{"error": "livre introuvable"}
C'est grave, et pas qu'esthétiquement. Les clients testent le code HTTP, pas le body : ils croient que tout va bien et continuent sur des données vides. Les caches se fient au code : un 200 peut être mis en cache, donc ton erreur aussi. Le monitoring compte les 4xx et 5xx pour t'alerter : noyée dans des 200, ta panne devient invisible. Le code doit dire la vérité : ressource absente, c'est 404, pas 200.
Un client envoie POST /api/emprunts pour emprunter le livre 42. Le JSON est parfait, le livre existe... mais il est déjà emprunté par quelqu'un d'autre. Ton API répond 400, 409 ou 422 ?
Voir la réponse
409 Conflict. Ce n'est pas 400 : la syntaxe est parfaite. Ce n'est pas 422 : le contenu est valide, le livre 42 existe et la demande a du sens. C'est l'état actuel qui refuse, le livre est déjà sorti. Quand la requête est correcte mais que le monde dit non, c'est 409.
L'arbre de décision du status code
Devant chaque réponse, pose-toi les questions dans l'ordre : ça a marché ? Si non, à qui la faute ? Et de quel genre ? Suis l'arbre, tu tombes sur le bon code.
À toi : fais parler ton API en status
Un terminal simulé branché sur l'API de la bibliothèque. Tu vas créer un livre, casser le JSON exprès, envoyer un contenu invalide, puis supprimer. À chaque coup, lis le code avant le body : il te dit déjà tout.
The code is already a sentence
Quick recap from the HTTP course: status codes come in families. 2xx it worked, 3xx look elsewhere, 4xx it's your fault (client), 5xx it's mine (server). You already know the eight basic codes. Here, we go up a notch.
On the API side, every response is a full sentence, and the code IS the meaning. Before even reading the JSON, your client reads the code and knows what to do. A book added to the library catalogue doesn't answer like a book already on loan, which doesn't answer like a badly formatted ISBN. Three situations, three different codes, three crisp sentences.
The API designer doesn't settle for "it worked / it didn't". They pick the right code for each business situation. That's the whole point of this lesson: learning to speak status fluently.
The success codes that say more than 200
Not every 2xx is a 200 OK. Two more precise codes tell a better story about what just happened.
201 Created: I created it, and here's where
When a POST /api/books succeeds and creates a resource, the right answer isn't 200, it's 201 Created. And it comes with a crucial header: Location, which says where the new resource lives.
HTTP/1.1 201 Created
Location: /api/books/87
The client doesn't have to guess the id of the book it just created: the API hands it over on a plate. It can chain straight into GET /api/books/87. A plain 200 with no Location says "all good" without saying "where": the client has to go digging.
204 No Content: success, nothing to add
204 No Content is the silent success. The operation worked and there's strictly nothing to return in the body. The two typical cases:
- a successful
DELETE /api/books/87: the book is gone, what more would you return? - a
PUTthat updates without needing to return the resource.
The body is empty, full stop. Returning 200 with {} or a "deleted successfully" message is less clean: 204 already says it all, in the code itself.
400 vs 422: the distinction that sets pros apart
Here's THE point of the lesson. On the 4xx side, two codes look alike and mean very different things. Telling them apart makes your API diagnosable.
400 Bad Request: the syntax is broken. The server can't even read the request. Malformed JSON, missing brace, extra comma. The message is unreadable, we stop at the door.422 Unprocessable Content: the syntax is fine, the server read the JSON perfectly, but the content is invalid on the business side. The title is missing, the ISBN is in the wrong format, the date is in the future. The sentence is well built, but it says something silly.
The simple image: 400 is a grammatically wrong sentence, we can't read it. 422 is a perfectly written sentence that's wrong on the substance. The server understands it, and refuses it.
422 is a safe code for any API. It's now called "Unprocessable Content" (no longer "Unprocessable Entity"). Above all, since RFC 9110 (2022), it's part of core HTTP: it's no longer reserved for WebDAV like it used to be. You can use it anywhere, with no second thoughts.
409 for conflict, 401/403 for access
409 Conflict: the state refuses
Sometimes the request is syntactically perfect AND valid on the substance, but the current state of the data makes it impossible. That's 409 Conflict.
- you want to borrow book 42, but it's already on loan to someone else;
- you create a book with an ISBN that already exists in the catalogue.
Nothing wrong with your request itself: it's the world that says no. It's not a 400 (the syntax is fine), nor a 422 (the content is valid): it's the state that blocks.
401 vs 403: not logged in vs not allowed
Two access codes people mix up all the time:
401 Unauthorized: you're not authenticated. No token, or an invalid token. The API doesn't even know who you are.403 Forbidden: the API knows perfectly well who you are (valid token), but you don't have the right. A regular reader trying to delete a book from the catalogue: they're logged in, but it's not for them.
We'll dig into tokens in lesson 7. Remember the line: 401 = "I don't know who you are", 403 = "I know who you are, and it's no".
The mistake that blinds an API
The deadly trap: answering 200 OK with an error hidden in the body. Something like:
HTTP/1.1 200 OK
Content-Type: application/json
{"error": "book not found"}
It's serious, and not just aesthetically. Clients test the HTTP code, not the body: they think all is well and carry on with empty data. Caches trust the code: a 200 can be cached, so your error gets cached too. Monitoring counts 4xx and 5xx to alert you: drowned in 200s, your outage goes invisible. The code must tell the truth: missing resource means 404, not 200.
A client sends POST /api/loans to borrow book 42. The JSON is perfect, the book exists... but it's already on loan to someone else. Does your API answer 400, 409 or 422?
Show the answer
409 Conflict. It's not 400: the syntax is perfect. It's not 422: the content is valid, book 42 exists and the request makes sense. It's the current state that refuses, the book is already out. When the request is correct but the world says no, it's 409.
The status code decision tree
For every response, ask the questions in order: did it work? If not, whose fault is it? And what kind? Follow the tree, you land on the right code.
Your turn: make your API speak status
A simulated terminal wired to the library API. You'll create a book, break the JSON on purpose, send invalid content, then delete. Each time, read the code before the body: it already tells you everything.
🎯 Pratique
S'entraîner (clique pour ouvrir) :
💬 Ré-explique sans regarder
Explique à un collègue la différence entre 400, 422 et 409, avec un exemple métier pour chacun.
400 = la syntaxe est cassée, le serveur ne peut pas lire la requête (JSON malformé). 422 = syntaxe OK, mais le contenu est invalide métier (titre manquant, ISBN au mauvais format). 409 = requête correcte et valide, mais l'état la refuse (livre déjà emprunté, ISBN déjà pris). En somme : on monte de « illisible » à « lisible mais faux » à « correct mais impossible vu l'état ».🧠 Rappel libre
Sans remonter : après un POST qui crée une ressource, quel code renvoies-tu, et quel header est obligatoire ? Et pour un DELETE réussi ?
201 Created, avec le header Location qui pointe vers la nouvelle ressource (ex. Location: /api/livres/87). Le client sait ainsi où la trouver. Pour un DELETE réussi sans rien à renvoyer : 204 No Content, body vide. Dans les deux cas, un simple 200 serait moins précis.⚖️ Juge le code de l'IA
Tu demandes à l'IA de gérer le cas « livre introuvable » dans ton API. Elle répond : « Réglé ! Je renvoie toujours 200 OK avec {"success": false} dans le body, ça simplifie le front : il n'a plus qu'un seul cas à gérer. » Tu acceptes, ou tu rejettes ?
200 qui cache une erreur dans le body rend l'API aveugle : les clients testent le code (ils croiront que tout va bien), les caches peuvent stocker un 200 (donc l'erreur aussi), et le monitoring ne voit plus les pannes noyées dans des 200. « Simplifier le front » ne justifie pas de mentir sur le code. Le bon réflexe : ressource absente → 404. Le code doit dire la vérité.POST tente de créer un compte avec un email déjà pris. Le JSON est valide, l'email est bien formé. Quel code ?{"titre":} : le JSON est cassé, le serveur n'arrive pas à le lire. Quel code, et lequel pour « pas connecté du tout » ?POST /api/emprunts pour le livre 42. Le JSON est parfait, le livre existe, mais il est déjà emprunté. Quel code, et lequel s'il n'avait simplement pas le droit d'emprunter ?Les codes parlent. Reste le contenu : le JSON, et les deux headers qui évitent les malentendus. Leçon 5 : le contrat de données.
Leçon 5 : JSON : le contrat de données →