@nodefony/framework — routes, contrôleurs, décorateurs
stable@nodefony/frameworkmis à jour 2026-07-19
C’est ici qu’on écrit son application.
@nodefony/httpconstruit le contexte d’une requête ; ce module décide quoi en faire : quelle route, quel contrôleur, quelle action, avec quels droits. Il porte la DX du framework — les décorateurs — et ses invariants — résolution ordonnée, idempotence, data plane d’administration. Un contrôleur y déclare ses actions HTTP et WebSocket avec les mêmes décorateurs.
📍 Documentation › @nodefony/framework
🧭 Par où commencer#
Trois parcours selon ce que tu viens faire. L’ordre compte : chaque étape suppose la précédente.
J’écris ma première route — le chemin le plus court vers une application qui répond.
- Décorateurs — la surface que tu tapes :
@controller,@Get,@Body,@Param. Commence ici, c’est la table de référence. - Contrôleurs — ce dont tu hérites, comment répondre, comment échouer proprement.
- Routage — pourquoi telle route gagne sur telle autre, et comment lire un
405.
Je débugge une route qui ne répond pas comme prévu.
- Routage — l’ordre de déclaration est la priorité ; la passe 405 ; les vhosts.
- Contrôleurs — l’ordre réel du cycle de vie, et ce que
initialize()peut ou non supposer. - Pipeline de requête — ce qui s’est passé avant que ta route soit même consultée.
Je fiabilise des mutations — paiements, commandes, tout ce qu’on ne veut pas jouer deux fois.
- Idempotence —
@Idempotent, la clé, les stores, ce qui se passe au rejeu. - Contrôleurs — codes de retour et réponses vides (204) sans piège.
- Sécurité — l’autorisation qui va avec.
🗂️ Les briques du module#
Le tableau pour choisir vite ; les cards en dessous pour savoir ce qu’on y trouve.
| Brique | Ce qu’elle résout | Tu en as besoin quand… |
|---|---|---|
| Décorateurs | déclarer routes, paramètres, réponses, gardes | toujours — c’est la surface d’écriture |
| Contrôleurs | recevoir la requête, répondre, gérer l’erreur | toujours |
| Routage | apparier une URL à une action, arbitrer, expliquer | deux routes se disputent, ou un 404/405 surprend |
| Idempotence | empêcher le double effet d’une mutation rejouée | paiement, commande, tout effet non rejouable |
| Admin (data plane) | monter les API d’admin /nodefony/<ns>/api/* |
ton module expose des stats ou actions à Studio et au CLI |
| Templates (Eta) | rendre des vues HTML côté serveur | tu renvoies des pages HTML plutôt que du JSON |
🏛️ Place dans le framework#
Le module s’appuie sur @nodefony/http (contexte, serveurs) et se fait garder par
@nodefony/security (firewall, CSRF). L’inverse n’est pas vrai : @nodefony/http ne peut pas
importer ce module — ce serait un cycle.
🧰 Surface publique#
Depuis une application : Controller, Router, Resolver, Route, controllers(), les décorateurs
de route, de paramètre et de garde, IdempotencyStore, AdminBroker. Les signatures exactes vivent
dans .ai/symbols.json et les types générés — jamais recopiées ici, où elles se périmeraient.
⚙️ Configuration#
Bloc Zod (nodefony/config/config.ts), déclaré depuis l’application via
use("@nodefony/framework", { … }) : router, adminBroker, et idempotency (choix du store et
réglages du GC — détaillé dans la page Idempotence).
📜 Normes appliquées#
RFC 9110 (méthodes, 405 et en-tête Allow, redirections), RFC 6455 §7.4 (codes de fermeture
WebSocket, dont le 1002 d’erreur de sous-protocole), et le brouillon IETF Idempotency-Key.
📡 Observabilité — Studio#
L’écran Routes liste la table telle qu’elle est réellement montée, et le Playground permet de
jouer une route en voyant ses badges @IsGranted / @Idempotent. Chaque module publie son data plane
via AdminBroker.
🧪 Tests & couverture#
Les chiffres exacts vivent dans la carte de l’aperçu, régénérée depuis vitest — jamais figés ici.
| Type | Où | Ce qui est prouvé |
|---|---|---|
| Unitaire | nodefony/tests/unit/** |
routeur, resolver, contrôleur, décorateurs, idempotence |
| Intégration | via @nodefony/http |
la route réelle répond sur un serveur vivant |
| E2E | via @nodefony/drizzle |
idempotence rejouée contre une vraie base |
⚠️ Pièges (symptôme → cause → correction)#
| Symptôme | Cause | Correction |
|---|---|---|
404 sur une route qui « existe » |
Contrôleur jamais importé — les routes naissent à l’import | L’ajouter à @controllers([…]) du module |
| Une route paramétrée mange un chemin littéral | L’ordre de déclaration est la priorité | Déclarer le littéral avant le paramétré |
| Action WebSocket jamais atteinte | Transport WEBSOCKET non déclaré sur la route |
L’ajouter aux méthodes de la route |
ce nom est RÉSERVÉ sur une action remove |
Le nom entre en collision avec un membre hérité de Service |
Renommer l’action — l’URL vient du décorateur |
| Double effet d’une mutation rejouée | Route sensible sans clé d’idempotence | Voir idempotence |
🔗 Pour aller plus loin#
- Le trajet complet d’une requête → pipeline-requete
- La couche transport en dessous → @nodefony/http
- Le pare-feu qui garde les actions → @nodefony/security
- Portées d’injection des contrôleurs → injection-portees
- Vue d’ensemble du framework → vue-ensemble