Saltar al contenido principal
Versión: 10.x

Inicio rápido

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

tRPC combina conceptos de REST y GraphQL. Si no estás familiarizado con ninguno, revisa los Conceptos clave.

Instalación

tRPC está dividido en varios paquetes, permitiéndote instalar solo lo necesario. Asegúrate de instalar los paquetes requeridos en las secciones adecuadas de tu base de código. Para esta guía rápida mantendremos la simplicidad usando solo el cliente vanilla. Para guías específicas de frameworks, consulta uso con React y uso con Next.js.

Requisitos
  • tRPC requiere TypeScript >= 4.7.0
  • Recomendamos encarecidamente usar "strict": true en tu tsconfig.json ya que no admitimos oficialmente el modo no estricto.

Comienza instalando los paquetes @trpc/server y @trpc/client:

sh
npm install @trpc/server @trpc/client
sh
npm install @trpc/server @trpc/client

Definir un enrutador backend

Exploraremos los pasos para construir una API con seguridad de tipos usando tRPC. Inicialmente, esta API contendrá tres endpoints con estas firmas de TypeScript:

ts
type User = { id: string; name: string; };
userList: () => User[];
userById: (id: string) => User;
userCreate: (data: { name: string }) => User;
ts
type User = { id: string; name: string; };
userList: () => User[];
userById: (id: string) => User;
userCreate: (data: { name: string }) => User;

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.ts
ts
import { initTRPC } from '@trpc/server';
 
/**
* Initialization of tRPC backend
* Should be done only once per backend!
*/
const t = initTRPC.create();
 
/**
* Export reusable router and procedure helpers
* that can be used throughout the router
*/
export const router = t.router;
export const publicProcedure = t.procedure;
server/trpc.ts
ts
import { initTRPC } from '@trpc/server';
 
/**
* Initialization of tRPC backend
* Should be done only once per backend!
*/
const t = initTRPC.create();
 
/**
* Export reusable router and procedure helpers
* that can be used throughout the router
*/
export const router = t.router;
export const publicProcedure = t.procedure;

Luego, inicializaremos nuestra instancia principal del enrutador, comúnmente llamada appRouter, a la que luego añadiremos procedimientos. Finalmente, necesitamos exportar el tipo del enrutador que usaremos más tarde en el lado del cliente.

server/index.ts
ts
import { router } from './trpc';
 
const appRouter = router({
// ...
});
 
// Export type router type signature,
// NOT the router itself.
export type AppRouter = typeof appRouter;
server/index.ts
ts
import { router } from './trpc';
 
const appRouter = router({
// ...
});
 
// Export type router type signature,
// NOT the router itself.
export type AppRouter = typeof appRouter;

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 consulta llamado userList que devuelve una lista de usuarios desde nuestra base de datos:

server/index.ts
ts
import { db } from './db';
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
userList: publicProcedure.query(async () => {
// Retrieve users from a datasource, this is an imaginary database
const users = await db.user.findMany();
const users: User[]
return users;
}),
});
server/index.ts
ts
import { db } from './db';
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
userList: publicProcedure.query(async () => {
// Retrieve users from a datasource, this is an imaginary database
const users = await db.user.findMany();
const users: User[]
return users;
}),
});

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:

The input parser can be any ZodType, e.g. z.string() or z.object().



server.ts
ts
import { z } from 'zod';
import { db } from './db';
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
// ...
userById: publicProcedure.input(z.string()).query(async (opts) => {
const { input } = opts;
const input: string
// Retrieve the user with the given ID
const user = await db.user.findById(input);
const user: User | undefined
return user;
}),
});
server.ts
ts
import { z } from 'zod';
import { db } from './db';
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
// ...
userById: publicProcedure.input(z.string()).query(async (opts) => {
const { input } = opts;
const input: string
// Retrieve the user with the given ID
const user = await db.user.findById(input);
const user: User | undefined
return user;
}),
});
información

En el resto de esta documentación, usaremos zod como nuestra biblioteca de validación.

4. Añadir un procedimiento de mutación

Similar a GraphQL, tRPC distingue entre procedimientos de consulta y mutación.

El funcionamiento de un procedimiento en el servidor no cambia mucho entre consulta y mutación. El nombre del método es diferente, y la forma en que el cliente usará este procedimiento cambia, ¡pero todo lo demás es igual!

Añadamos una mutación userCreate agregándola como nueva propiedad en nuestro objeto de enrutador:

server.ts
ts
const appRouter = router({
// ...
userCreate: publicProcedure
.input(z.object({ name: z.string() }))
.mutation(async (opts) => {
const { input } = opts;
const input: { name: string; }
// Create a new user in the database
const user = await db.user.create(input);
const user: { name: string; id: string; }
return user;
}),
});
server.ts
ts
const appRouter = router({
// ...
userCreate: publicProcedure
.input(z.object({ name: z.string() }))
.mutation(async (opts) => {
const { input } = opts;
const input: { name: string; }
// Create a new user in the database
const user = await db.user.create(input);
const user: { name: string; id: string; }
return user;
}),
});

Servir la API

Ahora que hemos definido nuestro enrutador, podemos servirlo. tRPC tiene muchos adaptadores para que puedas usar cualquier framework backend de tu elección. Para mantener la simplicidad, usaremos el adaptador standalone.

server/index.ts
ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { router } from './trpc';
 
const appRouter = router({
// ...
});
 
const server = createHTTPServer({
router: appRouter,
});
 
server.listen(3000);
server/index.ts
ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { router } from './trpc';
 
const appRouter = router({
// ...
});
 
const server = createHTTPServer({
router: appRouter,
});
 
server.listen(3000);
See the full backend code
server/db.ts
ts
type User = { id: string; name: string };
 
// Imaginary database
const users: User[] = [];
export const db = {
user: {
findMany: async () => users,
findById: async (id: string) => users.find((user) => user.id === id),
create: async (data: { name: string }) => {
const user = { id: String(users.length + 1), ...data };
users.push(user);
return user;
},
},
};
server/db.ts
ts
type User = { id: string; name: string };
 
// Imaginary database
const users: User[] = [];
export const db = {
user: {
findMany: async () => users,
findById: async (id: string) => users.find((user) => user.id === id),
create: async (data: { name: string }) => {
const user = { id: String(users.length + 1), ...data };
users.push(user);
return user;
},
},
};

server/trpc.ts
ts
import { initTRPC } from '@trpc/server';
 
const t = initTRPC.create();
 
export const router = t.router;
export const publicProcedure = t.procedure;
server/trpc.ts
ts
import { initTRPC } from '@trpc/server';
 
const t = initTRPC.create();
 
export const router = t.router;
export const publicProcedure = t.procedure;

server/index.ts
ts
import { createHTTPServer } from "@trpc/server/adapters/standalone";
import { z } from "zod";
import { db } from "./db";
import { publicProcedure, router } from "./trpc";
 
const appRouter = router({
userList: publicProcedure
.query(async () => {
const users = await db.user.findMany();
return users;
}),
userById: publicProcedure
.input(z.string())
.query(async (opts) => {
const { input } = opts;
const user = await db.user.findById(input);
return user;
}),
userCreate: publicProcedure
.input(z.object({ name: z.string() }))
.mutation(async (opts) => {
const { input } = opts;
const user = await db.user.create(input);
return user;
}),
});
 
export type AppRouter = typeof appRouter;
 
const server = createHTTPServer({
router: appRouter,
});
 
server.listen(3000);
server/index.ts
ts
import { createHTTPServer } from "@trpc/server/adapters/standalone";
import { z } from "zod";
import { db } from "./db";
import { publicProcedure, router } from "./trpc";
 
const appRouter = router({
userList: publicProcedure
.query(async () => {
const users = await db.user.findMany();
return users;
}),
userById: publicProcedure
.input(z.string())
.query(async (opts) => {
const { input } = opts;
const user = await db.user.findById(input);
return user;
}),
userCreate: publicProcedure
.input(z.object({ name: z.string() }))
.mutation(async (opts) => {
const { input } = opts;
const user = await db.user.create(input);
return user;
}),
});
 
export type AppRouter = typeof appRouter;
 
const server = 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.ts
ts
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from './server';
 
// 👆 **type-only** import
 
// Pass AppRouter as generic here. 👇 This lets the `trpc` object know
// what procedures are available on the server and their input/output types.
const trpc = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000',
}),
],
});
client/index.ts
ts
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from './server';
 
// 👆 **type-only** import
 
// Pass AppRouter as generic here. 👇 This lets the `trpc` object know
// what procedures are available on the server and their input/output types.
const trpc = createTRPCProxyClient<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 antes de enviarse al 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. Consultas y mutaciones

Ahora tienes acceso a tus procedimientos de API en el objeto trpc. ¡Pruébalo!

client/index.ts
ts
// Inferred types
const user = await trpc.userById.query('1');
const user: { name: string; id: string; } | undefined
 
const createdUser = await trpc.userCreate.mutate({ name: 'sachinraja' });
const createdUser: { name: string; id: string; }
client/index.ts
ts
// Inferred types
const user = await trpc.userById.query('1');
const user: { name: string; id: string; } | undefined
 
const createdUser = await trpc.userCreate.mutate({ name: 'sachinraja' });
const createdUser: { name: string; id: string; }

Autocompletado completo

Puedes abrir tu Intellisense para explorar tu API en el frontend. Encontrarás todas tus rutas de procedimientos esperándote, junto con los métodos para llamarlas.

client/index.ts
ts
// Full autocompletion on your routes
trpc.u;
      
client/index.ts
ts
// Full autocompletion on your routes
trpc.u;
      

¡Pruébalo tú mismo!

Próximos pasos

consejo

Te recomendamos encarecidamente que revises las aplicaciones de ejemplo para aprender cómo se instala tRPC en tu framework favorito.

consejo

Por defecto, tRPC mapeará tipos complejos como Date a su equivalente JSON (string en el caso de Date). Si quieres conservar la integridad de esos tipos, la forma más sencilla es usar superjson como Transformador de Datos.

tRPC incluye herramientas más sofisticadas del lado del cliente diseñadas para proyectos de React y Next.js.