Aller au contenu principal
Tous les articles
·3 min de lecture

tRPC v11 : une API full type-safe sans code generation

Zéro schéma GraphQL, zéro codegen, zéro runtime overhead — comment tRPC v11 change la façon de construire des API pour les SaaS Next.js.

trpctypescriptapibackend

Le problème avec REST et GraphQL

REST : vous écrivez votre API, puis vous écrivez les types côté client. Manuellement. À chaque changement. Et quand les types driftent... bug silencieux en production.

GraphQL : type safety, oui. Mais au prix d'un schéma à maintenir, un codegen à lancer, et un runtime qui parse chaque requête.

tRPC : vous écrivez votre API en TypeScript, et le client a les types automatiquement. Pas de codegen, pas de schéma, pas de runtime overhead.

Setup dans un SaaS Next.js

Le router tRPC

// src/server/api/routers/invoice.ts
import { z } from "zod";
import { createTRPCRouter, staffProcedure } from "~/server/api/trpc";
 
export const invoiceRouter = createTRPCRouter({
  getAll: staffProcedure.query(async ({ ctx }) => {
    return ctx.orgDb.invoice.findMany({
      orderBy: { createdAt: "desc" },
      include: { client: true },
    });
  }),
 
  create: staffProcedure
    .input(
      z.object({
        clientId: z.string(),
        items: z.array(
          z.object({
            description: z.string(),
            quantity: z.number().positive(),
            unitPrice: z.number().positive(),
          }),
        ),
      }),
    )
    .mutation(async ({ ctx, input }) => {
      return ctx.db.invoice.create({
        data: {
          organizationId: ctx.session.user.organizationId,
          clientId: input.clientId,
          items: { create: input.items },
        },
      });
    }),
});

Côté client — zéro configuration

"use client";
import { api } from "~/trpc/react";
 
export function InvoiceList() {
  const { data, isLoading } = api.invoice.getAll.useQuery();
 
  if (isLoading) return <Skeleton />;
 
  return (
    <div>
      {data?.map((invoice) => (
        // invoice est typé automatiquement — autocomplétion complète
        <InvoiceCard key={invoice.id} invoice={invoice} />
      ))}
    </div>
  );
}

Changez le type de retour côté serveur → TypeScript vous signale immédiatement les erreurs côté client. Avant même de lancer l'app.

La hiérarchie des procédures

tRPC v11 permet de chaîner des middlewares pour créer des niveaux d'accès :

// Du moins restrictif au plus restrictif
export const publicProcedure = t.procedure;
 
export const protectedProcedure = publicProcedure.use(enforceAuth);
 
export const staffProcedure = protectedProcedure.use(enforceStaffRole);
 
export const adminProcedure = protectedProcedure.use(enforceAdminRole);
 
// Permission granulaire
export const requirePermission = (perm: string) =>
  staffProcedure.use(({ ctx, next }) => {
    if (!hasPermission(ctx.session.user.role, perm)) {
      throw new TRPCError({ code: "FORBIDDEN" });
    }
    return next({ ctx });
  });

Chaque router choisit le bon niveau. Une query publique ? publicProcedure. Un CRUD admin ? requirePermission("invoices:write").

Validation avec Zod

tRPC s'intègre nativement avec Zod pour la validation d'input :

.input(
  z.object({
    search: z.string().optional(),
    page: z.number().int().positive().default(1),
    perPage: z.number().int().min(1).max(100).default(20),
  })
)

Le type de input dans votre handler est inféré automatiquement depuis le schéma Zod. Un seul endroit pour la validation ET les types.

Mutations optimistes

const utils = api.useUtils();
 
const createInvoice = api.invoice.create.useMutation({
  onSuccess: () => {
    // Invalider le cache pour refetch
    utils.invoice.getAll.invalidate();
  },
});

Pourquoi pas GraphQL ?

CritèretRPCGraphQL
CodegenNonOui
Runtime overheadZéroParsing + résolution
Setup10 min30 min + tooling
Type safetyFullFull (avec codegen)
Cas d'usageSaaS monorepoAPI publique multi-client

Règle simple : si votre API est consommée uniquement par votre frontend (SaaS), prenez tRPC. Si vous avez des clients externes (mobile tiers, partenaires), prenez GraphQL.

Conclusion

tRPC v11 élimine toute une catégorie de bugs — les types driftés entre client et serveur. Dans un SaaS où la vélocité compte, c'est un gain de productivité énorme.