ADR-04, API layer (Eden Treaty)
Eden Treaty + Elysia plutôt que tRPC. Pourquoi.
Statut : Accepté Date : 2026-04 Sujet : Choix de la couche API typée bout-en-bout pour Reciprok
Contexte
Reciprok a besoin d'une couche API qui :
- Type inference end-to-end entre serveur et client (frontend Next.js + tools IA)
- Intégration native avec Bun (notre runtime cible)
- Streaming pour le chat IA
- Lifecycle hooks pour brancher : auth, audit log (timeline events), métriques, logs
- Validation des inputs/outputs avec un schéma partagé
- Pas de codegen ou d'étape de build supplémentaire
Alternatives considérées
Option 1, tRPC + Express/Fastify
L'option historique de l'écosystème Better-T-Stack.
Pour :
- Écosystème mature, beaucoup d'exemples
- Type inference excellente
- Intégration React Query out of the box
Contre :
- Pas de support Bun first-class, tourne mais pas optimisé
- Couche d'abstraction supplémentaire (procedures vs routes HTTP)
- Lifecycle moins flexible que les hooks Elysia natifs
- Streaming SSE moins propre (subscriptions = WebSocket dans la doc tRPC)
- L'intégration avec OpenAPI nécessite un plugin tiers (
trpc-openapi) - Pas de macros : on duplique souvent les
middlewarepour les guards
Option 2, REST manuel + Zod + génération de types
Définir des routes REST classiques, valider avec Zod, et générer un client typé via OpenAPI.
Pour :
- Standard, lisible par n'importe quel dev
- OpenAPI gratuit
Contre :
- Codegen = étape de build supplémentaire
- Type inference moins fluide qu'Eden ou tRPC
- Beaucoup de boilerplate
Option 3, Elysia + Eden Treaty (retenu)
Elysia est un framework HTTP Bun-first, performant (~21x plus rapide qu'Express selon les benchmarks officiels), avec un système de type inference qui se propage à un client typé via le package @elysiajs/eden.
Pour :
- Bun-native : Reciprok tourne sur Bun, autant utiliser un framework conçu pour
- Type inference end-to-end sans codegen :
treaty<App>(...)infère les types directement depuis letypeof appexporté côté serveur. Aucun build, aucun fichier généré. - Lifecycle hooks first-class :
onRequest,parse,transform,beforeHandle,afterHandle,mapResponse,onAfterResponse,onError. Idéal pour brancher l'audit log, les métriques, GlitchTip. - Macros : système de "guards" réutilisables (auth, permissions, rate limit) qui s'attachent aux routes et propagent leur typage au client. Beaucoup plus propre que les middlewares tRPC.
- Modèle TypeBox : validation native, pas de wrapper Zod externe (mais Zod reste utilisable côté domaine si besoin)
- Plugin deduplication : si un module est mounté plusieurs fois (tests), il n'est exécuté qu'une fois
- Streaming SSE natif :
async function*qui yield les chunks, supporté nativement - OpenAPI auto-généré via
@elysiajs/swagger(un plugin officiel, pas un fork tiers) - Performance imbattable sur Bun
Contre :
- Plus jeune que tRPC, écosystème React Query un peu moins fourni
- Documentation parfois en avance sur les exemples publics
- Moins connu de la communauté → onboarding plus long pour un nouvel arrivant
Décision
Elysia côté serveur + Eden Treaty côté client.
// Server
export const app = new Elysia()
.use(appContext)
.use(authMacro)
.group('/api/v1', (api) => api.use(membersRoutes).use(requestsRoutes));
export type App = typeof app;
// Client
import { treaty } from '@elysiajs/eden';
import type { App } from '@reciprok/server';
export const api = treaty<App>(process.env.NEXT_PUBLIC_API_URL!);Le détail des best practices (method chaining, derive/decorate, macros, hooks, models) est dans la page Design d'API.
Conséquences
Positives :
- Pas de codegen, pas d'étape de build pour le client API
- Type inference end-to-end y compris pour les valeurs injectées par les macros (
user,member,traceId) - Hooks lifecycle natifs idéaux pour brancher la timeline et le monitoring
- Performance Bun maximale
- OpenAPI auto-généré sert aussi de doc pour les tools IA
Négatives :
- Onboarding nouveau dev : il faut lire la doc Elysia (ce qui est fait, le framework est bien documenté)
- Eden ne wrap pas encore parfaitement les streams SSE → on consomme avec
fetchnatif côté client pour le chat IA - Si on veut passer à un autre runtime (Node, Deno), Elysia tourne mais perd ses optimisations Bun
Migration depuis tRPC ?
Pas applicable : Reciprok est greenfield, on commence directement en Eden Treaty.
Voir aussi
- Design d'API, best practices Elysia détaillées
- ADR-06, Postgres self-host
- Documentation officielle Elysia
- Documentation Eden Treaty