一名开发者花了两个星期,将内部工具中的 REST API 替换成了 tRPC。

为什么这次切换至关重要

旧的技术栈迫使我们必须维护 DTO、校验器以及一套独立的用于前端的 TypeScript 类型。只要重命名一个后端字段,API 仍会返回 200,UI 会继续渲染,而 bug 最终只会以 “undefined” 值的形式出现。在团队成员发现问题之前,客户就已经发现了。REST 契约掩盖了问题,而额外的文件增加了维护成本,却从未带来回报。

原有的 REST 配置是怎样的

  • OpenAPI spec – 一个描述端点的静态文件,但从未充当过事实来源(source of truth)。
  • Client SDK generation step – 一个生成 JavaScript 包装器的 CI 任务。
  • Postman collection – 一个无人使用的共享测试产物。
  • Manual TypeScript interfaces – 必须与服务器保持同步的手写类型。

每次 API 变更都会影响其中至少三个产物,此外还要修改校验器和任何下游的 fetch 调用。这个过程既容易出错又缓慢。

tRPC 如何精简了代码库

tRPC 消除了独立的契约文件。服务器导出 router 类型,客户端导入同一个类型。重命名一个后端字段,编辑器会立即标记不匹配之处——无需运行代码,也无需等待请求失败。开发者删除了:

  • OpenAPI spec 文件。
  • Client SDK 生成步骤。
  • 不再使用的 Postman collection。
  • 手写 TypeScript 接口的文件夹。

代码库变得更加精简,反馈在开发阶段就能得到,而不是在部署之后。

tRPC 的局限性

只有当两端都使用 TypeScript 时,tRPC 才能发挥作用。在以下情况下它并不适用:

  • 移动端团队使用 Swift 或 Kotlin。
  • API 必须由外部合作伙伴调用。
  • 你需要一个公开的、与语言无关的接口。

迁移实际需要做些什么

这两周的工作不仅仅是复制粘贴。开发者必须:

  • 重写每一个 fetch 调用,改用 tRPC 的客户端函数。
  • 调整错误处理逻辑。
  • 更新依赖于原始 HTTP 响应的加载和重试状态的 UI 组件。

决策前需要思考的问题

  • 前端和后端都使用 TypeScript 吗? 如果没有共享的类型系统,tRPC 就会失去其核心优势。
  • 双方是否由同一个团队负责? 权责划分不清可能会重新导致契约漂移(contract drift)。
  • 你是在修复具体的 bug,还是在追逐潮流? 生产力的提升是真实的,但它应该用来解决现有的痛点。

2025 年的混合方案

许多团队通过同时运行这两套技术栈找到了平衡点:

  • tRPC 用于内部应用层,即代码库完全使用 TypeScript,且由同一个团队负责服务器和客户端。
  • REST 用于 Webhooks、公开 API 和合作伙伴集成,即需要与语言无关的访问方式。

为每个层面选择合适的工具,既能保持内部开发的快速,又能保留外部消费者所需的开放性。

总结: 将 REST 替换为 tRPC 可以消除重复的契约产物,并在编辑时暴露 bug,但只有当整个技术栈共享 TypeScript 且团队能够承担迁移成本时,这些收益才会真正实现。混合策略让你在享受收益的同时,不会将非 TypeScript 的消费者拒之门外。