Debug API par status code : 400, 403, 404, 413, 500 et le reste
Un seul guide pour debugger les erreurs HTTP (400, 403, 404, 413, 500…) : lire la famille du code, le détail exact, et chercher au bon endroit dès le départ.
Introduction
T'as cliqué sur un bouton. La donnée n'apparaît pas. Tu ouvres la console. Tu vois une erreur rouge. Et là, le réflexe classique :
- Tu changes le composant frontend
- Tu testes un autre endpoint
- Tu regénères ton token
- Tu demandes à une IA
- Tu passes 45 minutes à chercher
...alors que le status code HTTP te donnait la réponse depuis le début.
403 ne veut pas dire token invalide. Ça veut dire tu es connecté, mais tu n'as pas la permission. Ce n'est pas pareil. Et cette différence peut te faire perdre une heure.
Ce guide te donne une méthode simple : lire la famille du code en premier, le code exact ensuite, et debugger dans le bon sens dès le départ.
La méthode : famille d'abord, détail ensuite
Un status code HTTP se lit comme une adresse. La centaine te donne le quartier. Le chiffre exact te donne la porte.
2xx → succès 3xx → redirection ou cache 4xx → problème côté requête client 5xx → problème côté serveur ou infrastructure
Si tu retiens seulement ces quatre lignes, tu debugges déjà plus proprement que la majorité.
Codes 2xx — La requête a réussi
Quand tu vois un 2xx, l'API a bien reçu et traité ta requête. Le bug est ailleurs — probablement dans ce que ton code fait avec la réponse.
200 OK
La requête a réussi. Une réponse est disponible.
Ce que ça signifie : Le serveur a compris, exécuté, et retourné une réponse. Si quelque chose ne s'affiche pas, le bug est dans ta logique après la réponse.
À vérifier :
- La vraie forme du JSON reçu
- Les noms exacts des propriétés
- Les tableaux vides traités comme des erreurs
- Les valeurs
nullnon gérées - Une condition d'affichage incorrecte
Exemple de piège classique :
js// L'API retourne { data: { user: { name: "Elton" } } } // Mais ton code fait : const name = response.name // undefined // Alors que c'est : const name = response.data.user.name // ✅
201 Created
Une ressource vient d'être créée côté serveur.
Ce que ça signifie : Ton POST a fonctionné. L'objet existe maintenant. Tu dois souvent récupérer son id et synchroniser ton état local.
À vérifier :
- L'
idou l'objet retourné dans le body - La mise à jour du state local
- L'affichage du message de confirmation côté UI
Exemple :
jsconst response = await fetch("/api/posts", { method: "POST", body: JSON.stringify({ title: "Mon article" }) }) if (response.status === 201) { const newPost = await response.json() // ✅ Ajoute le nouvel objet dans ton state setPosts(prev => [...prev, newPost]) }
204 No Content
L'action a réussi, mais le serveur ne renvoie rien.
Ce que ça signifie : Succès silencieux. Souvent utilisé pour DELETE ou certaines actions simples. Il n'y a pas de body à parser.
Erreur typique :
js// ❌ Ça plantera — response.json() sur un body vide const data = await response.json() // ✅ Vérifie le status avant de parser if (response.status !== 204) { const data = await response.json() }
Codes 3xx — Redirection ou cache
Quand tu vois un 3xx, le serveur t'indique que la ressource a bougé, ou que tu peux utiliser une version en cache.
301 Moved Permanently
L'URL a changé définitivement.
À faire : Mets à jour l'endpoint dans tes variables d'environnement. L'ancienne adresse ne reviendra plus.
302 Found
Redirection temporaire.
À faire : Vérifie si ton client HTTP suit les redirects automatiquement. Inspecte le header Location pour voir la destination.
304 Not Modified
La ressource n'a pas changé depuis la dernière fois.
À faire : Le serveur te dit d'utiliser ta version en cache. Si tu vois des données obsolètes, inspecte tes headers Cache-Control et ETag.
Codes 4xx — Le problème vient de ta requête
C'est la famille la plus importante à maîtriser. Quand tu vois un 4xx, ne cherche pas du côté serveur. Inspecte ce que ton client envoie.
400 Bad Request
Ta requête est invalide. Le serveur comprend l'endpoint, mais pas ce que tu lui envoies.
Causes fréquentes :
- JSON mal formé
- Champ obligatoire absent
- Mauvais type de données
- Format de date invalide
bodyenvoyé alors que l'API attend desquery params
Checklist :
httpPOST /api/projects HTTP/1.1 Content-Type: application/json ← est-ce correct ? { "projectName": "AfriCreator" ← l'API attend peut-être "name" ? }
Exemple de diagnostic :
L'API répond 400. Le body d'erreur dit : "Field 'name' is required." Mon code envoie 'projectName'. → Je dois renommer le champ en 'name'.
401 Unauthorized
Le serveur ne reconnaît pas ton identité.
Causes fréquentes :
- Token absent
- Token expiré
- Token invalide ou mal formé
- Mauvais format du header d'autorisation
- Mauvais environnement (tu utilises un token de staging en prod)
À vérifier :
httpAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
- Le mot
Bearerest-il présent ? - Le token est-il encore valide ?
- Le token vient-il du bon environnement ?
Différence clé :
401 → "Je ne sais pas qui tu es." 403 → "Je sais qui tu es, mais t'as pas le droit."
403 Forbidden
Tu es reconnu, mais l'accès est refusé.
Causes fréquentes :
- Rôle insuffisant (
userau lieu d'admin) - Scope du token trop limité
- Ressource appartenant à un autre utilisateur
- Fonctionnalité non incluse dans le plan actuel
Piège classique :
js// Tu vois 403 → tu penses "token invalide" // Tu regénères un token → 403 encore // Parce que le problème n'est PAS le token // C'est que l'utilisateur n'a pas la permission d'accéder à cette route // ✅ Vérifie le rôle de l'utilisateur, pas son token
404 Not Found
La ressource est introuvable.
Causes fréquentes :
- Endpoint incorrect
- ID inexistant ou supprimé
- Mauvaise version d'API (
/v1au lieu de/v2) - Mauvaise méthode HTTP
Exemple de diagnostic :
js// Tu appelles : fetch("https://api.africreator.app/v1/posts/999") // → 404 // Vérifie : // 1. L'ID 999 existe-t-il en base ? // 2. La version /v1 est-elle la bonne ? // 3. La méthode est-elle GET ? // 4. L'environnement est-il le bon (local vs prod) ?
Cas classique en frontend :
Tout marche en local → 404 en production → Comparer les variables d'environnement → Souvent une URL de base ou un préfixe de route différent
413 Payload Too Large
La requête est trop lourde pour le serveur.
Causes fréquentes :
- Upload de fichier trop volumineux
- Body JSON énorme (base64 d'image inline, etc.)
- Limite nginx / API Gateway trop basse
À vérifier :
- Taille réelle du payload
- Compression ou upload multipart
- Limites
client_max_body_size/ config cloud
429 Too Many Requests
Tu envoies trop de requêtes. Le serveur te rate-limite.
Causes fréquentes :
- Boucle de requêtes
useEffectqui se déclenche à chaque rendu- Recherche sans debounce
- Retry automatique agressif
Exemple :
js// ❌ Chaque frappe envoie une requête API <input onChange={(e) => fetchResults(e.target.value)} /> // ✅ Avec debounce — attend 300ms d'inactivité const debouncedFetch = useMemo( () => debounce(fetchResults, 300), [] ) <input onChange={(e) => debouncedFetch(e.target.value)} />
Lis aussi le header Retry-After — il t'indique combien de secondes attendre avant de réessayer.
Codes 5xx — Le problème vient du serveur
Quand tu vois un 5xx, la requête est arrivée côté serveur, mais quelque chose a cassé là-bas. Ce n'est pas (forcément) ton code frontend.
500 Internal Server Error
Le serveur a rencontré une erreur inattendue.
Causes fréquentes :
- Exception non gérée dans le backend
- Variable d'environnement absente
- Données inattendues qui font crasher un traitement
- Problème de base de données
À faire :
- Lire les logs backend
- Reproduire la requête avec un client API comme Postman ou Insomnia
- Logger le payload exact reçu par le serveur
502 Bad Gateway
Un intermédiaire (proxy, load balancer) n'obtient pas une réponse valide de ta backend.
Causes fréquentes :
- Backend down
- Service upstream indisponible
- Mauvaise configuration du reverse proxy
- Déploiement instable
À faire : Vérifie la santé du service cible. Regarde les logs de ton infrastructure (Nginx, Vercel, Railway, etc.).
503 Service Unavailable
Le service n'est pas disponible pour l'instant.
Causes fréquentes :
- Maintenance en cours
- Surcharge
- Déploiement en cours
À faire : Vérifie la page de statut du service. Prévois un message utilisateur propre côté frontend au lieu d'afficher l'erreur brute.
504 Gateway Timeout
Un serveur intermédiaire attendait une réponse, mais elle n'est pas arrivée à temps.
Causes fréquentes :
- Requête SQL trop lente
- API externe lente
- Traitement synchrone trop long
Exemple :
js// L'utilisateur déclenche une action // Le backend appelle une API tierce // L'API tierce met 35 secondes à répondre // Le gateway timeout est à 30 secondes // → 504 // Solution : passer le traitement en tâche asynchrone (queue) // Et retourner immédiatement un 202 Accepted
Matrice de décision rapide
| Code | Ce que ça veut dire | Premier réflexe |
|---|---|---|
200 | Succès | Vérifier la logique après réponse |
201 | Ressource créée | Récupérer l'ID, synchroniser le state |
204 | Succès sans contenu | Ne pas parser de body |
301 | URL déplacée définitivement | Mettre à jour l'endpoint |
302 | Redirection temporaire | Inspecter le header Location |
304 | Pas de changement | Vérifier le cache |
400 | Requête invalide | Inspecter body, params et types |
401 | Non authentifié | Vérifier token et header auth |
403 | Non autorisé | Vérifier rôle, permission et scope |
404 | Introuvable | Vérifier URL, ID, route, environnement |
429 | Trop de requêtes | Ajouter debounce, cache ou backoff |
500 | Erreur serveur | Lire les logs backend |
502 | Upstream défaillant | Vérifier gateway, proxy, service amont |
503 | Service indisponible | Vérifier surcharge ou maintenance |
504 | Timeout | Identifier l'appel trop lent |
Workflow complet de debug
Quand tu tombes sur une erreur API, suis cet ordre. Pas l'inverse.
Étape 1 — Capture la vraie requête
Ne te fie pas à ce que tu crois envoyer. Vérifie ce qui part réellement :
✓ URL complète (avec le bon domaine et la bonne version) ✓ Méthode HTTP (GET, POST, PUT, PATCH, DELETE) ✓ Headers (Authorization, Content-Type...) ✓ Body (format, noms des champs, types) ✓ Query params ✓ Environnement (local, staging, prod)
Étape 2 — Lis la famille du status code
2xx ? → Succès. Cherche dans ta logique post-réponse. 3xx ? → Redirection ou cache. Vérifie URL et headers. 4xx ? → Problème client. Inspecte ta requête. 5xx ? → Problème serveur. Regarde les logs.
Étape 3 — Lis le body d'erreur complet
Le code ne suffit pas. L'API envoie souvent un message précis :
json{ "error": "Validation failed", "details": [ { "field": "email", "message": "Invalid email format" } ] }
Ce message est souvent plus utile que le code.
Étape 4 — Reproduis hors du frontend
Utilise Postman, Insomnia, ou curl pour isoler le problème :
bashcurl -X POST https://api.africreator.app/v1/posts \ -H "Authorization: Bearer <ton_token>" \ -H "Content-Type: application/json" \ -d '{"title": "Mon post", "content": "..."}'
Si ça marche ici → le bug est dans ton frontend. Si ça échoue ici → le bug est dans la requête ou l'API.
Étape 5 — Change une seule chose à la fois
Si tu modifies le token, l'URL, le body et un composant en même temps, tu ne sauras jamais ce qui a corrigé le problème.
Exemples de diagnostic complets
Exemple 1 — Le bouton supprimer semble marcher, mais l'élément revient
Symptôme : clic → l'élément disparaît → réapparaît après Status code : 204 No Content Diagnostic : la suppression côté API réussit. Le bug est dans la synchronisation du state local. Solution : filtrer l'élément supprimé dans le state immédiatement.
js// ✅ Supprimer localement après confirmation API if (response.status === 204) { setItems(prev => prev.filter(item => item.id !== deletedId)) }
Exemple 2 — L'admin ne peut pas accéder à une route protégée
Symptôme : clic sur "Accès admin" → erreur Status code : 403 Forbidden Réflexe faux : regénérer le token Bon réflexe : vérifier le rôle de l'utilisateur dans la BDD Découverte : le compte a été créé comme "user", pas "admin" Solution : mettre à jour le rôle côté base de données
Exemple 3 — La recherche plante après quelques frappes
Symptôme : l'utilisateur tape → erreur après 3-4 mots Status code : 429 Too Many Requests Diagnostic : une requête envoyée à chaque keystroke Solution : ajouter un debounce de 300ms
Exemple 4 — Tout marche en local, rien en production
Symptôme : fonctionnel en local, 404 en prod Status code : 404 Not Found Hypothèses à tester :
- Variable VITE_API_URL différente entre .env et .env.production
- Préfixe /v1 manquant en production
- Route non déployée côté backend Découverte : VITE_API_URL pointe sur localhost en prod (oubli de config)
Le mémo à garder
Colle ça dans ton espace de travail :
Debug API — Famille d'abord
2xx → succès → vérifier la logique après réponse 3xx → redirection/cache → vérifier URL et headers 4xx → problème client → inspecter requête, auth, permissions 5xx → problème serveur → vérifier logs, infra, dépendances
400 → corps de requête invalide 401 → non authentifié (token) 403 → non autorisé (permission/rôle) 404 → ressource introuvable (URL, ID, env) 429 → trop de requêtes (debounce) 500 → crash backend (logs) 504 → timeout (appel trop lent)
Conclusion
Un status code HTTP n'est pas juste une erreur dans la console.
C'est un signal. Une direction. Un raccourci de diagnostic.
L'API t'a déjà dit ce qui cloche.
Il te reste à apprendre à la lire.
— The KOF 👌
À lire ensuite
TypeScript en 2025 : Pourquoi c'est devenu incontournable
Découvrez pourquoi TypeScript est devenu le standard de facto pour tout projet JavaScript sérieux en 2025.
{"React","Architecture","Patterns"}Architecture React : Patterns et bonnes pratiques
Les patterns React essentiels pour construire des applications maintenables et scalables.