REST API design - 04 - Les codes de statut HTTP qu'il faut connaître

2xx, 3xx, 4xx, 5xx : quel code renvoyer, quand, et pourquoi 200-pour-tout est un anti-pattern.

  1. 01 REST API design - 00 - Pourquoi le design de ton API change tout
  2. 02 REST API design - 01 - Les principes REST que personne ne lit
  3. 03 REST API design - 02 - Des URLs qui ont du sens
  4. 04 REST API design - 03 - Les méthodes HTTP, pour de vrai
  5. 05 REST API design - 04 - Les codes de statut HTTP qu'il faut connaître
  6. 06 REST API design - 05 - Body, headers et le diable dans les détails
  7. 07 REST API design - 06 - La pagination, ou comment ne pas tuer ta base
  8. 08 REST API design - 07 - Filtrage et tri sans prise de tête
  9. 09 REST API design - 08 - La validation avec Zod, gardien de ton API
  10. 10 REST API design - 09 - Erreurs : un format que tes clients vont adorer
  11. 11 REST API design - 10 - Authentification : JWT, API keys et OAuth2
  12. 12 REST API design - 11 - Versioning : quand et comment faire évoluer ton API
  13. 13 REST API design - 12 - CORS : comprendre et debugger les erreurs cross-origin
  14. 14 REST API design - 13 - Rate limiting : protéger ton API sans frustrer tes clients
  15. 15 REST API design - 14 - Caching : les bonnes réponses sont celles qu'on n'envoie pas
  16. 16 REST API design - 15 - Upload de fichiers : multipart, signed URLs et streaming
  17. 17 REST API design - 16 - Relations entre ressources : embarquer, lier ou les deux
  18. 18 REST API design - 17 - HATEOAS : des liens dans tes réponses
  19. 19 REST API design - 18 - OpenAPI : le contrat entre ton API et le monde
  20. 20 REST API design - 19 - Documentation : une API non documentee est une API inutile
  21. 21 REST API design - 20 - Testing : tester ton API sans devenir fou
  22. 22 REST API design - 21 - Webhooks : quand c'est ton API qui appelle
  23. 23 REST API design - 22 - Performance : quand chaque milliseconde compte
  24. 24 REST API design - 23 - Sécurité : les attaques que tu vas subir (et comment t'en protéger)
  25. 25 REST API design - 24 - Glossaire : tous les termes REST API en un seul endroit

04 - Les codes de statut HTTP qu'il faut connaître

Ce que tu vas apprendre

  • Les codes de statut HTTP essentiels par famille (2xx, 3xx, 4xx, 5xx)
  • Quel code utiliser dans chaque situation concrète
  • Pourquoi renvoyer 200 pour tout est un anti-pattern destructeur
  • Comment implementer les bons codes dans Express

Prerequisites


Le projet ou tout etait 200

J'ai hérité d'une API ou chaque endpoint renvoyait 200. Succes ? 200 avec {"success": true}. Erreur de validation ? 200 avec {"success": false, "error": "Invalid email"}. Ressource introuvable ? 200 avec {"success": false, "error": "Not found"}. Erreur serveur ? 200 avec... tu devines.

Le monitoring voyait 100% de succes. Le CDN cachait les erreurs. Les tests e2e ne detectaient rien. Et moi je perdais mes cheveux.

Les codes de statut HTTP existent depuis 1990. Ils sont compris par chaque navigateur, proxy, load balancer, outil de monitoring et CDN de la planete. Les ignorer, c'est se battre contre toute l'infrastructure du web.

Famille 2xx -- Succes

200 OK

La réponse standard pour un succes. Utilise-la pour GET et PATCH/PUT qui renvoient des donnees.

httpGET /api/users/42 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json

{"id": 42, "name": "Alice"}

201 Created

Une ressource a ete créée. Toujours avec un POST (et parfois PUT). Inclus le header Location.

httpPOST /api/users HTTP/1.1
Content-Type: application/json

{"name": "Bob", "email": "bob@example.com"}

HTTP/1.1 201 Created
Location: /api/users/43

{"id": 43, "name": "Bob", "email": "bob@example.com"}

204 No Content

Succes, mais pas de body dans la réponse. Parfait pour DELETE et pour les mises à jour qui ne renvoient rien.

httpDELETE /api/users/42 HTTP/1.1

HTTP/1.1 204 No Content

En TypeScript :

typescriptrouter.delete("/api/users/:id", async (req, res) => {
  await userService.delete(req.params.id);
  res.status(204).end();
});

Famille 3xx -- Redirections

301 Moved Permanently

La ressource a définitivement change d'adresse. Les clients et moteurs de recherche doivent mettre à jour leurs liens.

304 Not Modified

Le client a une version cachee et elle est encore valide. Pas de body renvoye. Ca fonctionne avec les headers If-None-Match (ETag) ou If-Modified-Since.

httpGET /api/users/42 HTTP/1.1
If-None-Match: "abc123"

HTTP/1.1 304 Not Modified

Famille 4xx -- Erreur client

C'est la famille la plus riche et la plus mal utilisee.

400 Bad Request

La requête est malformee. JSON invalide, champ manquant, type incorrect.

typescriptrouter.post("/api/users", async (req, res) => {
  const result = userSchema.safeParse(req.body);

  if (!result.success) {
    return res.status(400).json({
      error: "Validation failed",
      details: result.error.issues,
    });
  }

  const user = await userService.create(result.data);
  res.status(201).json(user);
});

401 Unauthorized

Le client n'est pas authentifié. Pas de token, token expire, token invalide. Le nom est trompeur -- ca devrait s'appeler "Unauthenticated".

403 Forbidden

Le client est authentifié mais n'a pas les droits. Il sait qui il est, mais il n'a pas acces.

typescriptrouter.delete("/api/users/:id", async (req, res) => {
  if (req.user.role !== "admin") {
    return res.status(403).json({
      error: "Insufficient permissions",
    });
  }
  // ...
});

404 Not Found

La ressource n'existe pas. Simple, efficace, universel.

409 Conflict

La requête entre en conflit avec l'état actuel. Utile pour les emails dupliques, les conflits de version, les états incoherents.

typescriptrouter.post("/api/users", async (req, res) => {
  const existing = await userService.findByEmail(req.body.email);

  if (existing) {
    return res.status(409).json({
      error: "Email already registered",
    });
  }
  // ...
});

422 Unprocessable Entity

La requête est syntaxiquement valide mais semantiquement incorrecte. Le JSON est bien forme, mais les donnees n'ont pas de sens (date de fin avant la date de début, quantité negative...).

La frontiere avec 400 est floue. Mon approche : 400 pour les problèmes de format, 422 pour les problèmes de logique métier.

429 Too Many Requests

Rate limiting. Le client envoie trop de requêtes. Inclus le header Retry-After.

httpHTTP/1.1 429 Too Many Requests
Retry-After: 60

{"error": "Rate limit exceeded", "retryAfter": 60}

Famille 5xx -- Erreur serveur

500 Internal Server Error

Quelque chose a plante cote serveur. Le client n'y peut rien.

502 Bad Gateway

Le serveur agit comme proxy et a reçu une réponse invalide du serveur en amont. Courant avec les reverse proxies.

503 Service Unavailable

Le serveur est temporairement indisponible (maintenance, surcharge). Inclus Retry-After.

L'anti-pattern 200-pour-tout

Pourquoi c'est si grave ?

typescript// Anti-pattern : 200 pour tout
router.get("/api/users/:id", async (req, res) => {
  try {
    const user = await userService.findById(req.params.id);
    if (!user) {
      return res.json({ success: false, error: "Not found" }); // 200!
    }
    res.json({ success: true, data: user }); // 200!
  } catch (err) {
    res.json({ success: false, error: "Server error" }); // 200!
  }
});

// Correct : codes semantiques
router.get("/api/users/:id", async (req, res) => {
  try {
    const user = await userService.findById(req.params.id);
    if (!user) {
      return res.status(404).json({ error: "User not found" });
    }
    res.json(user);
  } catch (err) {
    res.status(500).json({ error: "Internal server error" });
  }
});

Avec les bons codes, ton monitoring sait que 4% de tes requêtes sont des 404, que les 500 ont spike a 3h du matin, que le rate limiting a bloque 200 requêtes. Avec 200 partout, tu es aveugle.

Retrouve un aide-mémoire complet des codes HTTP sur paltemps.fr.

Résumé

  • Utilise les codes de statut HTTP -- ils sont compris par toute l'infrastructure web
  • 201 pour les creations, 204 pour les suppressions, pas 200 pour tout
  • 400 pour les problèmes de format, 422 pour la logique métier, 409 pour les conflits
  • 401 = pas authentifié, 403 = pas autorise
  • L'anti-pattern 200-pour-tout rend ton monitoring inutile

Precedent : Les méthodes HTTP | Suivant : Body et headers

Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.