Démarrage rapide
Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →
Installation
tRPC est réparti entre plusieurs packages, vous pouvez donc n'installer que ce dont vous avez besoin. Assurez-vous d'installer les packages souhaités dans les sections appropriées de votre base de code. Pour ce guide de démarrage rapide, nous resterons simples et n'utiliserons que le client vanilla. Pour les guides spécifiques aux frameworks, consultez utilisation avec React et utilisation avec Next.js.
- tRPC nécessite TypeScript >=5.7.2
- Nous recommandons fortement d'utiliser
"strict": truedans votretsconfig.jsoncar nous ne prenons pas officiellement en charge le mode non strict.
Commencez par installer les packages @trpc/server et @trpc/client :
- npm
- yarn
- pnpm
- bun
- deno
npm install @trpc/server @trpc/client
yarn add @trpc/server @trpc/client
pnpm add @trpc/server @trpc/client
bun add @trpc/server @trpc/client
deno add npm:@trpc/server npm:@trpc/client
Si vous utilisez un agent de codage IA, installez les compétences tRPC pour une meilleure génération de code :
bashnpx @tanstack/intent@latest install
bashnpx @tanstack/intent@latest install
Votre première API tRPC
Parcourons les étapes de création d'une API typée avec tRPC. Pour commencer, cette API contiendra trois endpoints avec ces signatures TypeScript :
tstype User = { id: string; name: string; };userList: () => User[];userById: (id: string) => User;userCreate: (data: { name: string }) => User;
tstype User = { id: string; name: string; };userList: () => User[];userById: (id: string) => User;userCreate: (data: { name: string }) => User;
Voici la structure de fichiers que nous allons construire. Nous vous recommandons de séparer l'initialisation de tRPC, la définition du routeur et la configuration du serveur dans des fichiers distincts pour éviter les dépendances cycliques :
.├── server/│ ├── trpc.ts # tRPC instantiation & setup│ ├── appRouter.ts # Your API logic and type export│ └── index.ts # HTTP server└── client/└── index.ts # tRPC client
.├── server/│ ├── trpc.ts # tRPC instantiation & setup│ ├── appRouter.ts # Your API logic and type export│ └── index.ts # HTTP server└── client/└── index.ts # tRPC client
1. Créer une instance de routeur
D'abord, initialisons le backend tRPC. Il est recommandé de le faire dans un fichier séparé et d'exporter des fonctions d'aide réutilisables plutôt que l'objet tRPC complet.
server/trpc.tstsimport {initTRPC } from '@trpc/server';/*** Initialization of tRPC backend* Should be done only once per backend!*/constt =initTRPC .create ();/*** Export reusable router and procedure helpers* that can be used throughout the router*/export constrouter =t .router ;export constpublicProcedure =t .procedure ;
server/trpc.tstsimport {initTRPC } from '@trpc/server';/*** Initialization of tRPC backend* Should be done only once per backend!*/constt =initTRPC .create ();/*** Export reusable router and procedure helpers* that can be used throughout the router*/export constrouter =t .router ;export constpublicProcedure =t .procedure ;
Ensuite, nous initialiserons notre instance de routeur principale, communément appelée appRouter, à laquelle nous ajouterons ultérieurement des procédures. Enfin, nous devons exporter le type du routeur que nous utiliserons plus tard côté client.
server/appRouter.tstsimport {router } from './trpc';export constappRouter =router ({// ...});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {router } from './trpc';export constappRouter =router ({// ...});export typeAppRouter = typeofappRouter ;
2. Ajouter une procédure de requête
Utilisez publicProcedure.query() pour ajouter une procédure de requête au routeur.
Ce qui suit crée une procédure de requête appelée userList qui renvoie une liste d'utilisateurs :
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({userList :publicProcedure .query (async () => {constusers :User [] = [{id : '1',name : 'Katt' }];returnusers ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({userList :publicProcedure .query (async () => {constusers :User [] = [{id : '1',name : 'Katt' }];returnusers ;}),});export typeAppRouter = typeofappRouter ;
3. Utiliser un parseur d'entrée pour valider les inputs
Pour implémenter la procédure userById, nous devons accepter une entrée client. tRPC permet de définir des parseurs d'entrée pour valider et parser l'input. Vous pouvez définir votre propre parseur ou utiliser une bibliothèque de validation comme zod, yup ou superstruct.
Vous définissez votre parseur d'entrée dans publicProcedure.input(), accessible ensuite dans la fonction de résolution comme ci-dessous :
- Vanilla
- Zod
- Yup
- Valibot
The input parser should be a function that validates and casts the input of this procedure. It should return a strongly typed value when the input is valid or throw an error if the input is invalid.
Throughout the remainder of this documentation, we will use zod as our validation library.
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({// ...userById :publicProcedure // The input is unknown at this time. A client could have sent// us anything so we won't assume a certain data type..input ((val : unknown) => {// If the value is of type string, return it.// It will now be inferred as a string.if (typeofval === 'string') returnval ;// Uh oh, looks like that input wasn't a string.// We will throw an error instead of running the procedure.throw newError (`Invalid input: ${typeofval }`);}).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({// ...userById :publicProcedure // The input is unknown at this time. A client could have sent// us anything so we won't assume a certain data type..input ((val : unknown) => {// If the value is of type string, return it.// It will now be inferred as a string.if (typeofval === 'string') returnval ;// Uh oh, looks like that input wasn't a string.// We will throw an error instead of running the procedure.throw newError (`Invalid input: ${typeofval }`);}).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
The input parser can be any ZodType, e.g. z.string() or z.object().
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import {z } from 'zod';export constappRouter =router ({// ...userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import {z } from 'zod';export constappRouter =router ({// ...userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
The input parser can be any YupSchema, e.g. yup.string() or yup.object().
Throughout the remainder of this documentation, we will use zod as our validation library.
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import * asyup from 'yup';export constappRouter =router ({// ...userById :publicProcedure .input (yup .string ().required ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import * asyup from 'yup';export constappRouter =router ({// ...userById :publicProcedure .input (yup .string ().required ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
The input parser can be any Valibot schema, e.g. v.string() or v.object().
Throughout the remainder of this documentation, we will use zod as our validation library.
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import * asv from 'valibot';export constappRouter =router ({// ...userById :publicProcedure .input (v .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import * asv from 'valibot';export constappRouter =router ({// ...userById :publicProcedure .input (v .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
4. Ajouter une procédure de mutation
Comme GraphQL, tRPC établit une distinction entre les procédures Query et Mutation.
La distinction entre Query et Mutation est principalement sémantique. Les Query utilisent HTTP GET et sont destinées à des opérations de lecture, tandis que les Mutations utilisent HTTP POST et sont destinées à des opérations provoquant des effets de bord.
Ajoutons une mutation userCreate en la définissant comme nouvelle propriété de notre objet routeur :
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({// ...userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;// Create the user in your DBconstuser :User = {id : '1', ...input };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({// ...userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;// Create the user in your DBconstuser :User = {id : '1', ...input };returnuser ;}),});export typeAppRouter = typeofappRouter ;
Exposition de l'API
Maintenant que nous avons défini notre routeur, nous pouvons l'exposer. tRPC dispose d'adaptateurs de première classe pour de nombreux serveurs web populaires. Pour rester simple, nous utiliserons ici l'adaptateur Node.js standalone.
server/index.tstsimport {createHTTPServer } from '@trpc/server/adapters/standalone';import {appRouter } from './appRouter';constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
server/index.tstsimport {createHTTPServer } from '@trpc/server/adapters/standalone';import {appRouter } from './appRouter';constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
See the full backend code
server/trpc.tstsimport {initTRPC } from '@trpc/server';constt =initTRPC .create ();export constrouter =t .router ;export constpublicProcedure =t .procedure ;
server/trpc.tstsimport {initTRPC } from '@trpc/server';constt =initTRPC .create ();export constrouter =t .router ;export constpublicProcedure =t .procedure ;
server/appRouter.tstsimport {z } from "zod";import {publicProcedure ,router } from "./trpc";typeUser = {id : string;name : string };export constappRouter =router ({userList :publicProcedure .query (async () => {constusers :User [] = [{id : '1',name : 'Katt' }];returnusers ;}),userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;constuser :User = {id : '1', ...input };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {z } from "zod";import {publicProcedure ,router } from "./trpc";typeUser = {id : string;name : string };export constappRouter =router ({userList :publicProcedure .query (async () => {constusers :User [] = [{id : '1',name : 'Katt' }];returnusers ;}),userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;constuser :User = {id : '1', ...input };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/index.tstsimport {createHTTPServer } from "@trpc/server/adapters/standalone";import {appRouter } from "./appRouter";constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
server/index.tstsimport {createHTTPServer } from "@trpc/server/adapters/standalone";import {appRouter } from "./appRouter";constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
Utiliser votre nouveau backend côté client
Passons maintenant au code côté client pour découvrir la puissance de la sécurité des types de bout en bout. Lorsque nous importons le type AppRouter pour l'utiliser côté client, nous obtenons une sécurité typage complète pour notre système sans divulguer aucun détail d'implémentation au client.
1. Configurer le client tRPC
client/index.tstsimport {createTRPCClient ,httpBatchLink } from '@trpc/client';import type {AppRouter } from './appRouter';// 👆 **type-only** imports are stripped at build time// Pass AppRouter as a type parameter. 👇 This lets `trpc` know// what procedures are available on the server and their input/output types.consttrpc =createTRPCClient <AppRouter >({links : [httpBatchLink ({url : 'http://localhost:3000',}),],});
client/index.tstsimport {createTRPCClient ,httpBatchLink } from '@trpc/client';import type {AppRouter } from './appRouter';// 👆 **type-only** imports are stripped at build time// Pass AppRouter as a type parameter. 👇 This lets `trpc` know// what procedures are available on the server and their input/output types.consttrpc =createTRPCClient <AppRouter >({links : [httpBatchLink ({url : 'http://localhost:3000',}),],});
Les liens dans tRPC sont similaires à ceux de GraphQL, ils nous permettent de contrôler le flux de données vers le serveur. Dans l'exemple ci-dessus, nous utilisons le httpBatchLink, qui regroupe automatiquement plusieurs appels en une seule requête HTTP. Pour une utilisation plus approfondie des liens, consultez la documentation sur les liens.
2. Inférence de types et autocomplétion
Vous avez maintenant accès à vos procédures API via l'objet trpc. Essayez !
client/index.tsts// Inferred typesconstuser = awaittrpc .userById .query ('1');constcreatedUser = awaittrpc .userCreate .mutate ({name : 'Katt' });
client/index.tsts// Inferred typesconstuser = awaittrpc .userById .query ('1');constcreatedUser = awaittrpc .userCreate .mutate ({name : 'Katt' });
Vous pouvez également utiliser votre autocomplétion pour explorer l'API côté client
client/index.tststrpc .u ;
client/index.tststrpc .u ;
Prochaines étapes
| What's next? | Description |
|---|---|
| Example Apps | Explore tRPC in your chosen framework |
| TanStack React Query | Recommended React integration via @trpc/tanstack-react-query |
| Next.js | Usage with Next.js |
| Server Adapters | Express, Fastify, and more |
| Transformers | Use superjson to retain complex types like Date |