跳至主内容
版本:10.x

快速入门

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

tRPC 融合了 RESTGraphQL 的设计理念。如果您不熟悉这两种技术,建议先了解核心概念

安装

tRPC 由多个独立包组成,可按需安装。请确保在代码库的相应部分安装所需包。本快速入门指南将保持简洁,仅使用原生客户端。框架集成指南请查阅:React 使用指南Next.js 使用指南

系统要求
  • tRPC 要求 TypeScript >= 4.7.0
  • 强烈建议在 tsconfig.json 中设置 "strict": true,我们官方不支持非严格模式

首先安装 @trpc/server@trpc/client 这两个核心依赖包:

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

定义后端路由

接下来我们将逐步构建类型安全的 tRPC API。初始API包含三个端点,其 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. 创建路由实例

首先初始化 tRPC 后端。最佳实践是在独立文件中完成此操作,并导出可复用的辅助函数而非整个 tRPC 对象。

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;

接着初始化主路由实例(通常命名为 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;
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. 添加查询过程

使用 publicProcedure.query() 方法向路由添加查询过程。

以下示例创建名为 userList 的查询过程,返回数据库中的用户列表:

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. 使用输入解析器验证参数

要实现 userById 过程,需要接收客户端输入。tRPC 允许您定义输入解析器来验证和解析输入。您可以使用自定义解析器或第三方验证库,例如 zodyupsuperstruct

publicProcedure.input() 中定义输入解析器,解析结果可通过解析器函数访问:

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;
}),
});
信息

本文档后续内容将统一使用 zod 作为验证库。

4. 添加变更过程

与 GraphQL 类似,tRPC 区分查询(query)和变更(mutation)过程。

查询和变更过程在服务端的实现差异不大:方法名称不同,客户端调用方式不同,但核心机制完全一致。

通过向路由对象添加新属性来创建 userCreate 变更过程:

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;
}),
});

部署 API

完成路由定义后即可部署服务。tRPC 提供多种适配器,支持任意后端框架。为简化流程,我们将使用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);

在客户端使用后端服务

现在让我们转到客户端代码,体验端到端类型安全的强大功能。当我们将 AppRouter 类型导入客户端使用时,整个系统就实现了完整的类型安全,同时不会向客户端泄露任何实现细节。

1. 设置 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',
}),
],
});

tRPC 中的链接(Links)类似于 GraphQL 中的链接,它们允许我们在数据发送到服务器之前控制数据流。在上面的示例中,我们使用了 httpBatchLink,它会自动将多个调用合并为单个 HTTP 请求。有关链接的深入用法,请参阅链接文档

2. 查询与变更操作

现在您可以通过 trpc 对象访问您的 API 过程。立即尝试吧!

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; }

完整的自动补全功能

您可以打开智能感知(Intellisense)来探索前端中的 API。您会发现所有的过程路由都在等待调用,并附带对应的方法。

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

亲自尝试吧!

后续步骤

技巧

强烈建议您查看示例应用,了解如何在自己喜欢的框架中安装 tRPC。

技巧

默认情况下,tRPC 会将复杂类型(如 Date)映射为其 JSON 等效类型(对于 Date 就是 string)。如需保留这些类型的完整性,最简单的方法是使用 superjson 作为数据转换器。

tRPC 还包含专为 React 项目和 Next.js 设计的更高级客户端工具。