大家好,我是妍妍。今天想跟各位程序员朋友聊点实在的。
不知道你有没有遇到过这种情况:前端等接口等到心慌,后端改接口改到手软。一个页面要调十来个接口,有的数据多了用不上,有的数据少了还得再补一个。RESTful 用了这么多年,确实有点“老牛拉破车”的感觉了。
最近圈子里 GraphQL 和 tRPC 吵得火热。有人说 GraphQL 是未来,有人说 tRPC 才是真香。那到底该选哪个?妍妍今天就用大白话,帮大家把这笔账算清楚。
一、先说RESTful哪里“不得劲”了
RESTful 本身不差,设计得好也很优雅。但现实项目里,它常常遇到三个尴尬:
数据要么多要么少:一个接口返回50个字段,你只要5个。浪费流量不说,前端还得自己过滤。
请求数量爆炸:首页要显示用户信息、订单列表、商品推荐……调3个接口是起步,5个不嫌多。
版本管理头疼:/v1/users、/v2/users,改着改着自己都分不清哪个是哪个。
说白了,RESTful 是后端说了算——后端给什么,前端用什么。而新时代的开发,需要前端说了算——前端要什么,后端给什么。
二、GraphQL:我要什么你就给什么
GraphQL 的核心思想就一句话:前端自己描述需要哪些数据,后端只返回这些数据。
看个例子就懂了。假设我们要查一个用户的名字和最近三篇文章的标题。
代码模块1:GraphQL查询语句

query {
  user(id: "123") {
    name
    recentPosts(limit: 3) {
      title
    }
  }
}

返回的结果干干净净:
代码模块2:GraphQL返回结果

{
  "data": {
    "user": {
      "name": "妍妍",
      "recentPosts": [
        { "title": "GraphQL入门" },
        { "title": "tRPC实战" },
        { "title": "RESTful再见" }
      ]
    }
  }
}

是不是很舒服?一个请求,不多不少,刚好你想要的。
代码模块3:GraphQL服务端定义(简化)

const resolvers = {
  user: (parent, args) => getUserById(args.id),
  recentPosts: (user, args) => getPostsByUserId(user.id, args.limit)
};

三、tRPC:前后端类型一家亲
GraphQL 很强大,但有个小麻烦:前端和后端的类型得手动同步。你改了后端一个字段名,前端可能到运行时才发现报错。
tRPC 就是来解决这个问题的。它的口号是:不用写API文档,不用生成类型,直接从后端调函数。
代码模块4:tRPC后端定义

const appRouter = trpc.router({
  getUser: trpc.procedure
    .input(z.object({ id: z.string() }))
    .query(async ({ input }) => {
      return db. wWw.mir-cq.cOm.Cn ({ where: { id: input.id } });
    }),
});

export type AppRouter = typeof appRouter;

代码模块5:tRPC前端调用

const { data } = trpc.getUser.useQuery({ id: "123" });
console.log(data.name); // 完整类型提示,不会写错

看到了吗?前端调用 getUser 就像调用本地函数一样。TypeScript 会帮你检查参数类型和返回值。字段名写错了?编辑器直接划红线。
四、两者核心区别(一张表看懂)
对比项 GraphQL tRPC
学习成本 需要学Schema语法 会TypeScript就会
类型安全 靠工具生成类型 天生就是类型安全的
跨语言 支持任何语言 仅TypeScript/JavaScript
适合场景 开放API、多端接入 全栈TypeScript项目
网络开销 一次请求拿完 每次调用一个请求
五、问答环节1
问:妍妍,那是不是学了tRPC就不用学GraphQL了?
答: 不一定哦。如果你团队前后端都用TypeScript,项目是纯内部系统,tRPC确实爽。但如果你要做一个对外开放的API,给移动端、小程序、第三方开发者用,GraphQL更合适。tRPC像自家的私房菜,GraphQL像开给所有人的连锁餐厅。各有各的香。
六、到底该怎么选?妍妍给你三条建议
建议一:新项目、纯TypeScript团队 → 首选tRPC
不用写接口文档,不用维护类型,开发速度起飞。尤其适合后台管理系统、内部工具、创业项目MVP。
代码模块6:tRPC完整调用示例

// 后端定义
const postRouter = trpc.router({
  create: trpc.procedure
    .input(z.object({ title: z.string(), content: z.string() }))
    .mutation(async ({ input }) => db.post.create({ data: input })),
});

// 前端调用
const createMutation = trpc.post.create.useMutation();
createMutation.mutate({ title: "你好tRPC", content: "真香" });

建议二:多端接入、第三方调用 → 选GraphQL
如果你有iOS、安卓、Web、小程序,还有外部合作伙伴要调用API,GraphQL的生态和规范更成熟。
代码模块7:GraphQL批量获取示例

query {
  users(ids: ["1", "2", "3"]) {
    id
    name
    profile {
      avatar
      bio
    }
  }
}

建议三:老项目改造 → GraphQL做网关
不需要把老后端全重写,用GraphQL作为统一接入层,后面还是RESTful。前端只对接GraphQL,慢慢替换。
代码模块8:Apollo Server接入REST数据源

const { RESTDataSource } = require('@apollo/datasource-rest');

class UserAPI extends RESTDataSource {
  baseURL = 'https://old-api.example.com/';
  async getUser(id) {
    return this.get(`users/${id}`);
  }
}

七、不吹不黑,聊聊各自的“小脾气”
GraphQL的痛点:
缓存复杂(不像RESTful那样直接URL缓存)
容易出N+1查询问题(需要配合DataLoader)
后端压力可能变大(用户随便查深层数据)
tRPC的痛点:
只能用在TypeScript生态
每次请求都是一个独立调用(没有GraphQL那种一次拿多个资源的能力)
社区和工具链还在成长期
八、问答环节2
问:妍妍,GraphQL和tRPC可以一起用吗?
答: 当然可以。有些团队的做法是:内部管理系统用tRPC快速迭代,对外公开的API用GraphQL。两者不打架。甚至可以用tRPC去实现GraphQL的resolver,既享受类型安全,又提供开放能力。工具是死的,人是活的,怎么顺手怎么来。
九、写在最后
RESTful不会真正消失,就像jQuery今天还有人用一样。但我们必须承认:RESTful的年代,前后端是“商量着给数据”。GraphQL是“前端要什么给什么”。tRPC是“前端直接调后端”。
趋势很明显:AP.I正在变得越来越前端友好。
如果你是个人开发者或小团队,妍妍个人建议先从tRPC入手,上手快,体验爽。如果你在做企业级开放平台,GraphQL更稳妥。
不管选哪个,都比继续堆RESTful接口要强。别等到项目里几十个接口改不动了,才后悔没早换。
妍妍不写代码,但妍妍会告诉你哪条路更好走。
如果觉得有用,点赞、收藏、转发三连支持一下。下期我们聊聊“前端到底要不要学后端”,不见不散。