Skip to main content
Version: 10.x

定义过程

过程是暴露给客户端的函数,它可以是以下之一:

¥A procedure is a function which is exposed to the client, it can be one of:

  • 一个 Query - 用于获取数据,一般不改变任何数据

    ¥a Query - used to fetch data, generally does not change any data

  • 一个 Mutation - 用于发送数据,通常用于创建/更新/删除目的

    ¥a Mutation - used to send data, often for create/update/delete purposes

  • 一个 Subscription - 你可能不需要这个,我们有 专用文档

    ¥a Subscription - you might not need this, and we have dedicated documentation

tRPC 中的过程是创建后端函数的非常灵活的原语。它们使用不可变的构建器模式,这意味着你可以在多个过程之间共享功能。

¥Procedures in tRPC are very flexible primitives to create backend functions. They use an immutable builder pattern, which means you can create reusable base procedures that share functionality among multiple procedures.

编写过程

¥Writing procedures

你在 tRPC 设置期间创建的 t 对象返回一个初始 t.procedure,所有其他过程都基于该初始 t.procedure 构建:

¥The t object you create during tRPC setup returns an initial t.procedure which all other procedures are built on:

ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
 
const t = initTRPC.context<{ signGuestBook: () => Promise<void> }>().create();
 
export const router = t.router;
export const publicProcedure = t.procedure;
 
const appRouter = router({
// Queries are the best place to fetch data
hello: publicProcedure.query(() => {
return {
message: 'hello world',
};
}),
 
// Mutations are the best place to do things like updating a database
goodbye: publicProcedure.mutation(async (opts) => {
await opts.ctx.signGuestBook();
 
return {
message: 'goodbye!',
};
}),
});
ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
 
const t = initTRPC.context<{ signGuestBook: () => Promise<void> }>().create();
 
export const router = t.router;
export const publicProcedure = t.procedure;
 
const appRouter = router({
// Queries are the best place to fetch data
hello: publicProcedure.query(() => {
return {
message: 'hello world',
};
}),
 
// Mutations are the best place to do things like updating a database
goodbye: publicProcedure.mutation(async (opts) => {
await opts.ctx.signGuestBook();
 
return {
message: 'goodbye!',
};
}),
});

可重复使用 "基本过程"

¥Reusable "Base Procedures"

作为一般模式,我们建议你将 t.procedure 重命名并导出为 publicProcedure,这样你就可以为特定用例创建其他命名过程并导出它们。该模式称为 "基本过程",是 tRPC 中代码和行为重用的关键模式;每个应用都可能需要它。

¥As a general pattern we recommend you rename and export t.procedure as publicProcedure, which then makes room for you to create other named procedures for specific use cases and export those too. This pattern is called "base procedures" and is a key pattern for code and behaviour re-use in tRPC; every application is likely to need it.

下面的示例接受用户输入,并像保护城镇居民一样对他们进行 authorizes 处理。这显然是为了简单起见而设计的示例,而不是安全授权应用用户的适当方法,因此在实践中你可能希望使用 标头上下文中间件元数据authenticate 的某种组合并授权你的用户。

¥The below example takes a user input and authorizes them like protective towns-people. This is obviously a contrived example for simplicity, and not an appropriate way to securely authorize an application user, so in practice you may want to use some combination of Headers, Context, Middleware, and Metadata, to authenticate and authorize your users.

ts
export const authorizedProcedure = publicProcedure
.input(z.object({ townName: z.string() }))
.use((opts) => {
if (opts.input.townName !== 'Pucklechurch') {
throw new TRPCError({
code: 'FORBIDDEN',
message: "We don't take kindly to out-of-town folk",
});
}
 
return opts.next();
});
 
export const appRouter = t.router({
hello: authorizedProcedure.query(() => {
return {
message: 'hello world',
};
}),
goodbye: authorizedProcedure.mutation(async (opts) => {
await opts.ctx.signGuestBook();
 
return {
message: 'goodbye!',
};
}),
});
ts
export const authorizedProcedure = publicProcedure
.input(z.object({ townName: z.string() }))
.use((opts) => {
if (opts.input.townName !== 'Pucklechurch') {
throw new TRPCError({
code: 'FORBIDDEN',
message: "We don't take kindly to out-of-town folk",
});
}
 
return opts.next();
});
 
export const appRouter = t.router({
hello: authorizedProcedure.query(() => {
return {
message: 'hello world',
};
}),
goodbye: authorizedProcedure.mutation(async (opts) => {
await opts.ctx.signGuestBook();
 
return {
message: 'goodbye!',
};
}),
});