Inicio rápido
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Instalación
tRPC está dividido en varios paquetes, así que puedes instalar solo lo que necesites. Asegúrate de instalar los paquetes en las secciones adecuadas de tu códigobase. Para esta guía de inicio rápido, lo mantendremos simple y usaremos solo el cliente vanilla. Para guías de frameworks, consulta uso con React y uso con Next.js.
- tRPC requiere TypeScript >=5.7.2
- Recomendamos encarecidamente usar
"strict": trueen tutsconfig.jsonya que no admitimos oficialmente el modo no estricto.
Comienza instalando los paquetes @trpc/server y @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 utilizas un agente de programación con IA, instala habilidades de tRPC para mejorar la generación de código:
bashnpx @tanstack/intent@latest install
bashnpx @tanstack/intent@latest install
Tu primera API con tRPC
Exploraremos los pasos para construir una API con seguridad de tipos usando tRPC. Inicialmente, esta API contendrá tres endpoints con estas firmas de 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;
Esta es la estructura de archivos que construiremos. Recomendamos separar la inicialización de tRPC, la definición del router y la configuración del servidor en archivos distintos para evitar dependencias cíclicas:
.├── 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. Crear una instancia de enrutador
Primero, inicialicemos el backend de tRPC. Es una buena convención hacer esto en un archivo separado y exportar funciones auxiliares reutilizables en lugar del objeto tRPC completo.
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 ;
A continuación, inicializaremos nuestra instancia principal del router, comúnmente llamada appRouter, a la que luego añadiremos procedimientos. Finalmente, necesitamos exportar el tipo del router que usaremos más tarde en el lado del cliente.
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. Añadir un procedimiento de consulta
Usa publicProcedure.query() para añadir un procedimiento de consulta al enrutador.
Lo siguiente crea un procedimiento de query llamado userList que devuelve una lista de usuarios:
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. Usar un analizador de entrada para validar inputs
Para implementar el procedimiento userById, necesitamos aceptar entrada del cliente. tRPC te permite definir analizadores de entrada para validar y procesar la entrada. Puedes definir tu propio analizador o usar una biblioteca de validación de tu elección, como zod, yup o superstruct.
Defines tu analizador de entrada en publicProcedure.input(), que luego se puede acceder en la función resolutora como se muestra a continuación:
- 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. Añadir un procedimiento de mutación
Similar a GraphQL, tRPC distingue entre procedimientos de Query y Mutation.
La distinción entre Query y Mutation es principalmente semántica. Las Queries usan HTTP GET y están destinadas a operaciones de lectura, mientras que las Mutations usan HTTP POST y están pensadas para operaciones que causan efectos secundarios.
Añadamos una mutación userCreate agregándola como nueva propiedad en nuestro objeto de enrutador:
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 ;
Servir la API
Ahora que hemos definido nuestro router, podemos servirlo. tRPC tiene adaptadores de primera clase para muchos servidores web populares. Para mantenerlo simple, usaremos aquí el adaptador standalone para Node.js.
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);
Usar tu nuevo backend en el cliente
Ahora pasemos al código del lado del cliente y aprovechemos el poder de la seguridad de tipos de extremo a extremo. Cuando importamos el tipo AppRouter para que el cliente lo use, logramos una seguridad de tipos completa en nuestro sistema sin filtrar detalles de implementación al cliente.
1. Configurar el cliente de 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',}),],});
Los links en tRPC son similares a los links en GraphQL: nos permiten controlar el flujo de datos hacia el servidor. En el ejemplo anterior, usamos el httpBatchLink, que agrupa automáticamente múltiples llamadas en una sola solicitud HTTP. Para un uso más avanzado de links, consulta la documentación de links.
2. Inferencia de tipos y autocompletado
Ahora tienes acceso a tus procedimientos de API en el objeto trpc. ¡Pruébalo!
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' });
También puedes usar tu autocompletado para explorar la API desde tu cliente
client/index.tststrpc .u ;
client/index.tststrpc .u ;
Próximos pasos
| 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 |