WakaStart
Utilisation de l'API

Erreurs — Codes HTTP

Format d'erreur unifié, codes HTTP 400 à 5xx, causes et stratégies de gestion pour une Wakapp robuste.

Version v1.04 min de lecture

Erreurs — Codes HTTP

L'API WakaStart utilise un format d'erreur unifié (NestJS standard). Chaque code HTTP a une sémantique précise.


Format d'erreur unifié

json
{ "statusCode": 403, "message": "Niveau d'administration insuffisant. Requis: CustomerAdmin, Actuel: User", "error": "Forbidden" }

Pour les erreurs de validation (400) avec plusieurs champs invalides :

json
{ "statusCode": 400, "message": [ "email must be an email", "firstName should not be empty", "profileId must be a UUID" ], "error": "Bad Request" }

Champs :

ChampTypeDescription
statusCodenumberCode HTTP
messagestring | string[]Description lisible du problème
errorstringLibellé HTTP standard

400 — Bad Request

Données invalides. Le body n'a pas passé la validation DTO.

Causes fréquentes :

  • Email non valide
  • Email de domaine jetable (yopmail, mailinator…)
  • UUID manquant ou malformé
  • Champ obligatoire absent
  • Valeur hors enum (teamLevel doit être NONE | VIEWER | CONTRIBUTOR | MEMBER | MANAGER | ADMIN)
  • Token d'invitation invalide/expiré/déjà utilisé (lors de /accept)

Action : Corriger le body de la requête et retenter.


401 — Unauthorized

Authentification manquante ou invalide.

Cas 1 — Token enrichi manquant

json
{ "statusCode": 401, "message": "Token enrichi manquant ou invalide", "error": "Unauthorized" }

Causes :

  1. Header x-enriched-token absent — vérifier le proxy serveur
  2. Cookie wakastart_token non posé (l'appel à /api/auth/enrich a échoué)
  3. Token enrichi expiré — procéder au refresh
  4. Claim organization absent du JWT Keycloak (Organizations Keycloak non configurées)
  5. keycloak_id en DB ne correspond pas au sub Keycloak

Action : Tenter un refresh token (une seule fois). Si le refresh échoue → redirect login.

Cas 2 — Token Bearer expiré ou invalide

Action : Refresh proactif ou redirect login.

Cas 3 — API Key invalide

json
{ "statusCode": 401, "message": "Invalid API key", "error": "Unauthorized" }

Action : Vérifier la clé API (format sk_live_... ou sk_test_...).


402 — Payment Required

Crédits insuffisants pour une opération consommant des crédits.

json
{ "statusCode": 402, "message": "Insufficient credits", "error": "Payment Required" }

Action : Rediriger vers la page d'achat de crédits (/billing/credits).


403 — Forbidden

L'utilisateur est authentifié mais n'a pas les droits nécessaires.

Cas 1 — Niveau admin insuffisant

json
{ "statusCode": 403, "message": "Niveau d'administration insuffisant. Requis: CustomerAdmin, Actuel: User", "error": "Forbidden" }

Cas 2 — Droit applicatif manquant

json
{ "statusCode": 403, "message": "Droit requis : users.create", "error": "Forbidden" }

Cas 3 — Feature désactivée

json
{ "statusCode": 403, "message": "La fonctionnalité invitation n'est pas activée pour ce customer", "error": "Forbidden" }

Action : Afficher un message clair à l'utilisateur. Ne pas retenter automatiquement.


404 — Not Found

L'entité demandée n'existe pas ou n'est pas visible depuis le scope du token.

Anti-BOLA : un CustomerAdmin qui essaie d'accéder à un Customer qui ne lui appartient pas verra un 404 (pas un 403). C'est intentionnel pour ne pas révéler l'existence de l'entité (OWASP BOLA pattern).

Action : Vérifier que l'identifiant (WID ou UUID) est correct et appartient au tenant accessible.


409 — Conflict

Une contrainte d'unicité est violée.

Cas courants :

  • Email déjà utilisé dans le Customer
  • Invitation PENDING déjà existante pour cet email + Customer
  • Subdomain déjà utilisé par un autre Network

Action : Adapter l'UI pour informer l'utilisateur du conflit.


429 — Too Many Requests

Rate limit dépassé.

Headers : Retry-After: 2 (durée en secondes avant de pouvoir retenter)

Action : Respecter le Retry-After et implémenter un backoff exponentiel.

typescript
const retryAfter = parseInt(res.headers.get("Retry-After") ?? "2", 10); await new Promise(r => setTimeout(r, retryAfter * 1000)); // 1 seul retry, puis échouer proprement

5xx — Erreurs serveur

Causes possibles :

  • Service downstream injoignable (Keycloak, ws-serv-config, ws-serv-token)
  • Erreur Prisma (contrainte DB inattendue)
  • Timeout interne
  • Problème de provisioning Keycloak (lors d'/accept invitation)

Action : Retenter avec backoff exponentiel (max 3 tentatives). Si persistant, contacter le support avec le x-request-id.

typescript
// Toujours logger le request-id pour le support const requestId = res.headers.get("x-request-id"); if (requestId) logger.error("API 500", { requestId, url, method });

Gestion d'erreurs recommandée côté frontend

typescript
class ApiError extends Error { constructor( public readonly status: number, public readonly body: { statusCode: number; message: string | string[]; error: string } ) { super(Array.isArray(body.message) ? body.message.join(", ") : body.message); } get isForbidden() { return this.status === 403; } get isUnauthorized(){ return this.status === 401; } get isConflict() { return this.status === 409; } get isRateLimit() { return this.status === 429; } get isServerError() { return this.status >= 500; } }

Aller plus loin