tRPC vs REST
tRPC (RPC type-safe, TypeScript full-stack) face à l'API REST (agnostique au langage, standard) — comparaison de conception d'API. Type safety, écosystème, scalabilité.
Zéro codegen, sécurité de type TypeScript de bout en bout
Langage de requête universel, schema-first, pour clients multiples
Décidez selon votre contexte : la seule « sécurité de type » n'est pas un argument suffisant pour GraphQL. Si vous utilisez un seul monorepo TypeScript avec un seul client web, tRPC demande presque toujours moins de travail — zéro codegen, et un changement côté serveur devient immédiatement une erreur TS côté client. Si vous avez une application mobile, une API publique ouverte aux développeurs externes ou un besoin de fédération multi-équipes, le contrat de schéma indépendant du langage de GraphQL et l'écosystème Apollo Federation offrent un avantage structurel.
| Catégorie | tRPC | GraphQL |
|---|---|---|
| Performance | 7/10 | 6/10 |
| Facilité d'apprentissage | 8/10 | 5/10 |
| Écosystème | 6/10 | 9/10 |
| Communauté | 7/10 | 8/10 |
| Marché de l'emploi | 5/10 | 8/10 |
| Pérennité | 7/10 | 8/10 |
// tRPC — définition du router (serveur)
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
// db = client Prisma/ORM (importé depuis un fichier séparé)
const t = initTRPC.create();
export const appRouter = t.router({
getUser: t.procedure
.input(z.object({ id: z.string() }))
.query(async ({ input }) => {
return db.user.findUnique({ where: { id: input.id } });
}),
});
export type AppRouter = typeof appRouter;
// Client — le type du serveur est inféré automatiquement, pas de codegen
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from './server';
const client = createTRPCClient<AppRouter>({
links: [httpBatchLink({ url: 'http://localhost:3000/trpc' })],
});
const user = await client.getUser.query({ id: '1' });
// user: { id: string; name: string; ... } — sécurité de type complète à la compilation// graphql-js + @apollo/server — schéma, resolver et serveur dans un seul fichier
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
// db = client Prisma/ORM (importé depuis un fichier séparé)
const typeDefs = `#graphql
type Post {
id: ID!
title: String!
}
type User {
id: ID!
name: String!
posts: [Post!]!
}
type Query {
user(id: ID!): User
}
`;
const resolvers = {
Query: {
user: (_parent, { id }, { db }) => db.user.findUnique({ where: { id } }),
},
User: {
posts: (user, _args, { db }) =>
db.post.findMany({ where: { authorId: user.id } }),
},
};
const server = new ApolloServer({ typeDefs, resolvers });
const { url } = await startStandaloneServer(server, {
context: async () => ({ db }),
listen: { port: 4000 },
});
console.log(`Serveur prêt : ${url}`);
// Requête client — seuls les champs nécessaires sont sélectionnés :
// query { user(id: "1") { name posts { title } } }Décidez selon votre contexte : la seule « sécurité de type » n'est pas un argument suffisant pour GraphQL. Si vous utilisez un seul monorepo TypeScript avec un seul client web, tRPC demande presque toujours moins de travail — zéro codegen, et un changement côté serveur devient immédiatement une erreur TS côté client. Si vous avez une application mobile, une API publique ouverte aux développeurs externes ou un besoin de fédération multi-équipes, le contrat de schéma indépendant du langage de GraphQL et l'écosystème Apollo Federation offrent un avantage structurel.
Obtenir une consultation gratuiteSi vous travaillez dans un seul monorepo TypeScript avec un seul client web, tRPC demande moins de code et de configuration (zéro codegen, inférence TS de bout en bout — trpc.io). Si vous avez une application mobile, une API publique ouverte aux développeurs externes ou plusieurs services indépendants, le contrat de schéma de GraphQL et son écosystème de fédération (Apollo Federation) offrent une abstraction plus adaptée.