Utilisation de l'API
Erreurs — Codes métier
Codes d'erreur métier Wakastart, messages exacts testables programmatiquement et mappings d'état.
Version v1.03 min de lecture
Erreurs — Codes métier
Ce chapitre liste les messages d'erreur avec valeur exacte et stable que vous pouvez tester programmatiquement. Lisez Erreurs HTTP pour les codes HTTP standard.
Messages stricts (testables programmatiquement)
Certains message ont une valeur exacte et stable :
| Message | Status | Signification |
|---|---|---|
"Token enrichi manquant ou invalide" | 401 | wakaToken absent ou invalide |
"Insufficient credits" | 402 | Quota crédits dépassé |
"La fonctionnalité invitation n'est pas activée pour ce customer" | 403 | Feature invitation désactivée |
"Invalid API key" | 401 | Clé API inconnue ou révoquée |
"Invitation non trouvée" | 200 (valid: false) | Token d'invitation inconnu (via verify) |
"Cette invitation a déjà été acceptée" | 200 (valid: false) | Token déjà utilisé |
"Cette invitation a expiré" | 200 (valid: false) | expiresAt < now() |
"Cette invitation a été annulée" | 200 (valid: false) | Statut CANCELLED |
Note : les messages
verifyretournent toujours200avec{ valid: false, errorMessage: "..." }— pas un code d'erreur HTTP.
Erreurs d'invitation — traitement exhaustif
typescript// Gérer les 4 états d'erreur d'une invitation async function loadInvitation(token: string) { const res = await fetch(`/api/proxy/invitations/verify/${token}`); const { valid, invitation, errorMessage } = await res.json(); if (!valid) { switch (errorMessage) { case "Cette invitation a expiré": return { error: "expired", ui: "Ce lien d'invitation a expiré. Demandez un nouveau lien." }; case "Cette invitation a déjà été acceptée": return { error: "accepted", ui: "Ce compte existe déjà. Connectez-vous directement." }; case "Cette invitation a été annulée": return { error: "cancelled", ui: "Cette invitation a été annulée par l'administrateur." }; case "Invitation non trouvée": default: return { error: "not_found", ui: "Ce lien d'invitation est invalide." }; } } return { valid: true, invitation }; }
Erreurs de droits — messages structurés
Les erreurs 403 liées aux droits contiennent des informations structurées dans message :
typescript// Extraire le niveau requis vs niveau actuel d'un 403 function parseAdminLevelError(message: string) { const match = message.match(/Requis: (\w+), Actuel: (\w+)/); if (match) { return { required: match[1], actual: match[2] }; } return null; } // Usage const error = parseAdminLevelError( "Niveau d'administration insuffisant. Requis: CustomerAdmin, Actuel: User" ); // → { required: "CustomerAdmin", actual: "User" }
Codes de rate limit par endpoint
Certains endpoints ont des messages de rate limit spécifiques qui permettent d'identifier l'endpoint concerné :
typescript// Pattern de détection rate limit function isRateLimitError(status: number, headers: Headers): boolean { return status === 429 && headers.has("Retry-After"); } function getRateLimitWait(headers: Headers): number { return parseInt(headers.get("Retry-After") ?? "2", 10) * 1000; }
Erreurs de validation — parsing
Pour les 400 avec tableau de messages, construire une map de champs en erreur :
typescriptinterface ValidationErrors { [field: string]: string[]; } function parseValidationErrors( messages: string | string[] ): ValidationErrors { const msgs = Array.isArray(messages) ? messages : [messages]; const result: ValidationErrors = {}; for (const msg of msgs) { // Format NestJS : "fieldName must be ..." const firstSpace = msg.indexOf(" "); if (firstSpace > -1) { const field = msg.substring(0, firstSpace); const error = msg.substring(firstSpace + 1); result[field] = [...(result[field] ?? []), error]; } } return result; } // Usage avec react-hook-form try { await createUser(dto); } catch (err) { if (err instanceof ApiError && err.status === 400) { const fieldErrors = parseValidationErrors(err.body.message); Object.entries(fieldErrors).forEach(([field, errors]) => { form.setError(field as any, { message: errors[0] }); }); } }
Erreurs de conflit (409) — stratégies
typescripttry { await createInvitation(dto); toast.success("Invitation envoyée"); } catch (err) { if (err instanceof ApiError && err.isConflict) { const msg = err.body.message as string; if (msg.includes("invitation") && msg.includes("PENDING")) { // Invitation déjà existante — proposer de renvoyer setConflictAction("resend"); } else if (msg.includes("utilisateur")) { // Utilisateur déjà dans le Customer toast.error("Cet email est déjà utilisé dans ce Customer."); } } }
Aller plus loin
- Erreurs HTTP : codes 400-5xx complets
- Invitations — Vérification : traitement des
valid: false - Pièges classiques : diagnostic des erreurs récurrentes