Erreurs

FougereError représente une erreur métier avec un code typé. Les handlers la lèvent et les couches suivantes conservent son code, son message et ses détails.

throw new FougereError({
  code: ErrorCode.CONFLICT,
  message: `Le slug '${slug}' est déjà pris`,
  entity: 'post',
  operation: 'create',
  // details?: [{ path, message }]   — par champ, utilisé par VALIDATION_FAILED
  // cause?: unknown
});

Les codes

CodeSensProjection HTTP
VALIDATION_FAILEDentrée invalide — details contient les { path, message } par champ400
UNAUTHORIZEDpas d'identité401
FORBIDDENidentité présente, droit absent403
NOT_FOUNDla chose désignée n'existe pas404
CONFLICTl'état refuse la transition (déjà publié, slug pris)409
SERVICE_UNAVAILABLEune Frond distante est injoignable503
INTERNAL_ERRORtout l'inattendu500

ErrorCode en porte douze autres, chacun projeté sur le statut HTTP du même nom : BAD_REQUEST 400, METHOD_NOT_ALLOWED 405, REQUEST_TIMEOUT 408, GONE 410, PRECONDITION_FAILED 412, PAYLOAD_TOO_LARGE 413, UNPROCESSABLE_ENTITY 422, LOCKED 423, TOO_MANY_REQUESTS 429, NOT_IMPLEMENTED 501, BAD_GATEWAY 502, GATEWAY_TIMEOUT 504. Les sept ci-dessus sont ceux qu'un domaine emploie ; les autres existent pour qu'une surface n'ait jamais à inventer un statut que le vocabulaire porte.

INTERNAL_ERROR est le seul dont le message ne sort pas

Les autres codes ont été écrits pour l'appelant et voyagent entiers. Un INTERNAL_ERROR, non : il peut citer un chemin, une requête ou une ligne, donc il est remplacé par une constante avant de quitter le process.

Il est journalisé au même endroit — masquer et enregistrer vivent dans la même fonction, pour que la phrase existe exactement une fois, sur le serveur. Un opérateur qui cherche « pourquoi ce 500 » la trouve dans les logs avec sa cause, son entité et son opération ; un attaquant ne la voit jamais. Si votre message doit atteindre l'appelant, c'est qu'il ne s'agit pas d'un INTERNAL_ERROR : donnez-lui son code.

Propagation d'une erreur

  1. Le handler lève une FougereError — le même objet que la Frond soit locale ou distante.
  2. Appel local — l'erreur se propage en mémoire, intouchée.
  3. Appel distant — le transport la met en trame JSON-RPC (code: -32000, data: { code, message, entity, operation, details? }) et le côté appelant la reconstruit une FougereError, avec ses details.
  4. Dans une pageuseQuery/useCommand l'exposent comme error (une vraie FougereError) ; useFormFor mappe automatiquement VALIDATION_FAILED.details sur les erreurs par champ.
  5. Sur la surface RESTtoHttpError projette le code vers le vrai statut HTTP (table ci-dessus), la valeur typée entière dans data.

Le navigateur reçoit le même code, le même message et les mêmes erreurs par champ, que la Frond soit locale ou distante. Un hôte inaccessible produit une erreur typée SERVICE_UNAVAILABLE.

Ordre des vérifications

Le blog de ce site effectue les vérifications dans cet ordre :

requireUser(user)        // UNAUTHORIZED
requireOwn(id, user)   // NOT_FOUND, puis FORBIDDEN
→ vérifs d'état          // CONFLICT (déjà publié, brouillon vide)
→ réaliser               // storage.update(…)

Suite : Seeds — initialiser les données par les opérations.

Construit avec Fougere — ce site tourne sur le framework qu'il documente.