tRPC 中的 RPC 是 Remote Procedure Call,也就是远程过程调用。
如果前端和后端都使用 TypeScript,tRPC 可以让双方共享 API 类型。后端定义过程、输入和返回值,前端调用时就能获得参数提示、返回值推导和编译期错误检查。
tRPC 是一个面向 TypeScript 应用的端到端类型安全 RPC 框架。
后端可以定义类似 userById、post.list、post.create 这样的过程;前端则像调用类型安全函数一样调用它们。实际网络通信仍然通过 HTTP 完成,只是 tRPC 帮我们封装了路径、参数、序列化和类型推导。
它适合:
它不适合把内部 API 直接当作公共 API 使用。若主要消费者是 Python、Java、C# 或 Go 客户端,REST/OpenAPI、GraphQL 或 gRPC 通常更合适。
Router 用来组织 API,Procedure 是一个可以被远程调用的过程。常见过程类型包括:
一个 Router 可以嵌套成多个业务领域,例如 user、post、order。最终客户端会得到类似 trpc.post.list 和 trpc.post.create 的类型安全调用入口。
tRPC 通常与 Zod 配合。后端为输入定义 Zod Schema,既可以帮助 TypeScript 推导类型,也可以在运行时校验来自网络的真实输入。
这是必要的,因为 TypeScript 类型在编译后会被擦除,不能单独保护网络请求。任何用户提交的数据都应该进行运行时校验。
Context 保存一次请求中多个过程都需要的信息,例如:
Procedure 可以从 Context 读取这些公共资源,从而避免每个接口重复初始化。
Middleware 适合实现登录检查、角色权限、日志、计时和限流等通用逻辑。
常见做法是定义 publicProcedure 和 protectedProcedure:公开接口使用前者,需要登录的接口使用后者。这样业务代码不需要反复编写鉴权逻辑。
前端调用某个 tRPC 过程后,通常会经历:
因此,tRPC 并没有绕过网络,而是把 HTTP API 封装成了类型安全的远程过程调用。
后端通常导出整个应用 Router 的类型,例如 AppRouter。客户端使用这个类型创建 tRPC 客户端,再配置 HTTP 链接器。
React 项目中,最常见的组合是 tRPC React 客户端加 TanStack Query。组件可以使用自动推导类型的查询和变更 Hook。
读取数据时,客户端能知道:
提交数据时,Mutation 可以处理:
TanStack Query 主要负责缓存、重新请求、重试和请求状态;tRPC 主要负责过程路径、输入输出类型和传输层,两者职责不同但配合很好。
在 Next.js Server Components 中,也可以直接使用服务端 caller 或更底层的业务服务。服务器调用自己的服务时,不一定需要再绕一圈发送 HTTP 请求。
常见组合包括:
React + TanStack Query 是目前最容易找到资料和示例的组合。
tRPC 可以接入:
Router 可以与具体 Web 框架分离,所以同一套业务 API 可以根据需要挂载到不同服务器上。
tRPC 不要求特定数据库,常见组合包括:
其他常见配套工具还有:
对于初学者和现代 TypeScript 全栈项目,我推荐:
Next.js + TypeScript + tRPC + TanStack Query + Zod + PostgreSQL + Drizzle + Better Auth + Tailwind CSS。
它们的职责分别是:
如果团队已经熟悉 Prisma,可以使用 Prisma 替代 Drizzle。选择一个稳定、团队熟悉的 ORM,比追逐工具差异更重要。
REST 是最通用的 Web API 形式,OpenAPI 可以生成多语言客户端、接口文档、Mock Server 和校验代码。
适合公共 API、跨语言客户端、微服务和需要标准化文档的团队。缺点是需要维护更多显式 Schema 和客户端代码。
GraphQL 让客户端选择需要的字段,适合多个页面数据需求差异很大、需要聚合多个后端服务的场景。
它的能力强,但需要维护 Schema、Resolver、缓存和权限,整体复杂度通常高于 tRPC。
gRPC 基于 Protocol Buffers,适合内部微服务、跨语言通信、高性能调用和流式通信。浏览器使用时通常还需要 gRPC-Web 或网关。
Connect RPC 使用 Protobuf,同时兼顾 RPC 模式、HTTP 和浏览器环境。它适合希望使用 RPC,但又需要跨语言 Schema 和更标准工具链的团队。
可以遵循一个简单原则:
tRPC 和 REST 并不冲突。常见做法是:内部 TypeScript 前端使用 tRPC,外部系统使用单独设计的 REST API,两者共享同一套业务服务和数据库访问层。
推荐的分层结构是:
REST Handler / tRPC Procedure ↓ Application Service ↓ Repository / Database
在 Next.js 中,可以创建 app/api/public/posts/route.ts,为外部系统提供 GET、POST、PUT 或 DELETE 接口。
REST Handler 不应该复制一份完整业务逻辑,而应该调用共享的 post service。tRPC Procedure 也调用同一个 service。
这样既能让内部前端获得端到端类型安全,又能为外部系统提供稳定的 HTTP API。
部分 tRPC 生态工具可以把 Router 或 Procedure 转换为 OpenAPI,并生成 REST 风格的路径和文档。
这种方案适合想尽量复用 tRPC 定义的团队,但要检查:
并不是每个 RPC 过程都天然适合 REST。复杂动作型接口经常需要人工设计公开路径。
如果外部 API 很重要,可以把它作为明确的 Public API 层维护:
不要把内部 Router 的全部过程直接暴露给外部系统。公开 API 应该只暴露稳定、必要且经过权限设计的能力。
可以按 user、post、order 等业务领域拆分 Router,避免出现一个几千行的 API 文件。
Procedure 负责输入校验、Context 获取和调用服务。复杂业务应放到 Application Service 或领域层,这样 REST、定时任务和消息消费者也能复用。
默认应谨慎开放接口。需要登录的功能使用受保护过程,需要角色控制的功能还要进行权限检查。
调用方应该依据稳定的错误码和字段处理失败,而不是依赖可能变化的错误文本。
类型安全不能替代生产运维。项目仍然需要日志、错误追踪、慢查询监控、权限审计、限流、单元测试和端到端测试。
tRPC 的核心价值,是让 TypeScript 前后端共享同一份 API 类型,并把接口调用变成编辑器能够理解和检查的代码。
它特别适合前后端由同一团队维护的 TypeScript 全栈应用,但不一定适合作为所有公共 API 的唯一方案。
最重要的架构原则是:tRPC 是传输和类型安全层,不是业务层。把业务逻辑放在可复用的服务层中,内部客户端可以享受 tRPC 的开发体验,外部系统也可以通过稳定的 REST API 接入。
暂无评论,快来抢沙发吧!