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
| Code | Sens | Projection HTTP |
|---|---|---|
VALIDATION_FAILED | entrée invalide — details contient les { path, message } par champ | 400 |
UNAUTHORIZED | pas d'identité | 401 |
FORBIDDEN | identité présente, droit absent | 403 |
NOT_FOUND | la chose désignée n'existe pas | 404 |
CONFLICT | l'état refuse la transition (déjà publié, slug pris) | 409 |
SERVICE_UNAVAILABLE | une Frond distante est injoignable | 503 |
INTERNAL_ERROR | tout l'inattendu | 500 |
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
- Le handler lève une
FougereError— le même objet que la Frond soit locale ou distante. - Appel local — l'erreur se propage en mémoire, intouchée.
- 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 uneFougereError, avec sesdetails. - Dans une page —
useQuery/useCommandl'exposent commeerror(une vraieFougereError) ;useFormFormappe automatiquementVALIDATION_FAILED.detailssur les erreurs par champ. - Sur la surface REST —
toHttpErrorprojette le code vers le vrai statut HTTP (table ci-dessus), la valeur typée entière dansdata.
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.