name: tRPC Patterns description: 端到端类型安全的APIs与tRPC,实现客户端和服务器之间的无缝TypeScript集成,无需代码生成。
tRPC Patterns
概览
tRPC使得构建无需编写单独模式或生成代码的类型安全API成为可能。类型在客户端和服务器之间自动共享,非常适合TypeScript monorepos和全栈应用。
为什么这很重要
- 零代码生成:自动推断类型,无需代码生成步骤
- 端到端类型安全:在编译时捕获API错误
- 出色的开发体验:IDE中API调用的自动补全
- 小包:客户端开销最小
核心概念
1. 路由器定义
// server/trpc.ts
import { initTRPC, TRPCError } from '@trpc/server';
import { Context } from './context';
const t = initTRPC.context<Context>().create();
export const router = t.router;
export const publicProcedure = t.procedure;
export const protectedProcedure = t.procedure.use(isAuthed);
// 中间件
const isAuthed = t.middleware(({ ctx, next }) => {
if (!ctx.user) {
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
return next({ ctx: { user: ctx.user } });
});
2. 程序(端点)
// server/routers/user.ts
import { z } from 'zod';
import { router, publicProcedure, protectedProcedure } from '../trpc';
export const userRouter = router({
// 查询(GET)
getById: publicProcedure
.input(z.object({ id: z.string().uuid() }))
.query(async ({ input, ctx }) => {
return ctx.prisma.user.findUnique({ where: { id: input.id } });
}),
// 变更(POST/PUT/DELETE)
updateProfile: protectedProcedure
.input(z.object({
name: z.string().min(1).max(100),
bio: z.string().max(500).optional(),
}))
.mutation(async ({ input, ctx }) => {
return ctx.prisma.user.update({
where: { id: ctx.user.id },
data: input,
});
}),
// 订阅(WebSocket)
onNewMessage: protectedProcedure
.subscription(({ ctx }) => {
return observable<Message>((emit) => {
const onMessage = (msg: Message) => emit.next(msg);
ctx.ee.on('newMessage', onMessage);
return () => ctx.ee.off('newMessage', onMessage);
});
}),
});
3. 应用路由器
// server/routers/_app.ts
import { router } from '../trpc';
import { userRouter } from './user';
import { postRouter } from './post';
import { commentRouter } from './comment';
export const appRouter = router({
user: userRouter,
post: postRouter,
comment: commentRouter,
});
export type AppRouter = typeof appRouter;
4. 客户端设置(React)
// utils/trpc.ts
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from '../server/routers/_app';
export const trpc = createTRPCReact<AppRouter>();
// 提供器设置
function App() {
const [queryClient] = useState(() => new QueryClient());
const [trpcClient] = useState(() =>
trpc.createClient({
links: [
httpBatchLink({
url: '/api/trpc',
headers: () => ({
authorization: getAuthToken(),
}),
}),
],
}),
);
return (
<trpc.Provider client={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>
<MyApp />
</QueryClientProvider>
</trpc.Provider>
);
}
5. 在组件中使用
// 完全类型安全和自动补全!
function UserProfile({ userId }: { userId: string }) {
// 查询
const { data: user, isLoading } = trpc.user.getById.useQuery({ id: userId });
// 变更
const updateProfile = trpc.user.updateProfile.useMutation({
onSuccess: () => {
utils.user.getById.invalidate({ id: userId });
},
});
// 乐观更新
const utils = trpc.useUtils();
const handleUpdate = (name: string) => {
updateProfile.mutate({ name });
};
if (isLoading) return <Spinner />;
return <div>{user?.name}</div>;
}
快速开始
-
安装包:
npm install @trpc/server @trpc/client @trpc/react-query @tanstack/react-query zod -
创建tRPC实例:
// server/trpc.ts import { initTRPC } from '@trpc/server'; const t = initTRPC.create(); export const router = t.router; export const publicProcedure = t.procedure; -
定义你的路由器:
export const appRouter = router({ hello: publicProcedure .input(z.object({ name: z.string() })) .query(({ input }) => `Hello ${input.name}`), }); -
设置API处理器(Next.js):
// pages/api/trpc/[trpc].ts import { createNextApiHandler } from '@trpc/server/adapters/next'; export default createNextApiHandler({ router: appRouter }); -
在组件中使用:
const { data } = trpc.hello.useQuery({ name: 'World' });
生产清单
- [ ] 使用自定义错误格式化进行错误处理
- [ ] 使用Zod模式进行输入验证
- [ ] 速率限制中间件
- [ ] 认证中间件
- [ ] 请求日志记录
- [ ] 响应缓存策略
- [ ] 为性能配置批处理链接
- [ ] 如果需要,设置WebSocket订阅
- [ ] 为外部消费者生成OpenAPI(可选)
反模式
- 跳过输入验证:始终使用Zod模式进行输入验证
- 庞大的路由器:按领域拆分路由器,不要将所有内容放在一个文件中
- 程序中的业务逻辑:保持程序简洁,委托给服务
- 忽略错误处理:使用适当的TRPCError代码进行客户端处理
集成点
- Next.js:
@trpc/server/adapters/next - Express:
@trpc/server/adapters/express - Fastify:
@trpc/server/adapters/fastify - Prisma:在上下文中直接集成
- NextAuth:在上下文中会话
- React Query:
@trpc/react-query
进一步阅读
- tRPC文档
- tRPC + Next.js示例
- T3堆栈 - Next.js + tRPC + Prisma + NextAuth