← 返回资讯
赵一鸣
产品评测编辑
已审核

从 REST 到 GraphQL:真实项目迁移实录

我们花了 3 个月把 API 从 REST 迁移到 GraphQL。以下是完整记录。

从 REST 到 GraphQL:真实项目迁移实录

从 REST 到 GraphQL:真实项目迁移实录

我们花了 3 个月把 API 从 REST 迁移到 GraphQL。以下是完整记录。

迁移前:REST 的问题

TYPESCRIPT
// 获取用户 + 订单 + 商品信息需要 3 个请求
const user = await fetch('/api/users/1')
const orders = await fetch('/api/users/1/orders')
const products = await Promise.all(
  orders.map(o => fetch(`/api/products/${o.productId}`))
)

迁移方案:渐进式

不是一次性重写,而是逐步添加 GraphQL 层:

CODE
客户端 ──→ GraphQL Gateway ──→ REST API (原有)
                              ──→ 新 GraphQL Resolver

第 1 周:搭建 GraphQL 网关

TYPESCRIPT
// server/src/graphql/schema.ts
import { builder } from './builder'

const UserRef = builder.objectRef<User>('User')

builder.queryFields(t => ({
  user: t.field({
    type: UserRef,
    args: { id: t.arg.string({ required: true }) },
    resolve: async (_, { id }) => {
      // 调用原有 REST API
      const res = await fetch(`http://localhost:3000/api/users/${id}`)
      return res.json()
    }
  })
}))

第 2 周:添加关联查询

TYPESCRIPT
builder.objectType(UserRef, {
  fields: t => ({
    id: t.exposeString('id'),
    name: t.exposeString('name'),
    orders: t.field({
      type: [OrderRef],
      resolve: async (user) => {
        const res = await fetch(`http://localhost:3000/api/users/${user.id}/orders`)
        return res.json()
      }
    })
  })
})

第 3 周:解决 N+1 问题

TYPESCRIPT
import DataLoader from 'dataloader'

const orderLoader = new DataLoader(async (userIds: string[]) => {
  const orders = await db.orders.findMany({
    where: { userId: { in: userIds } }
  })
  return userIds.map(id => orders.filter(o => o.userId === id))
})

builder.objectType(UserRef, {
  fields: t => ({
    orders: t.field({
      type: [OrderRef],
      resolve: async (user) => orderLoader.load(user.id)
    })
  })
})

迁移成果

| 指标 | REST | GraphQL |

|------|------|---------|

| 首页请求数 | 12 | 3 |

| 首页传输量 | 45KB | 18KB |

| 前端代码量 | ~2000 行 | ~800 行 |

踩坑记录

1. 不要一次性重写,渐进式迁移

2. 必须有 DataLoader,否则 N+1 问题严重

3. 做好缓存,GraphQL 默认 POST 不利于 HTTP 缓存

4. 限制查询深度,防止恶意嵌套查询

216
7219 阅读
5 评论
分享
链接已复制
编辑说明

本文由 MakeSense 编辑团队撰写并审核。文中引用的数据和观点均经过交叉验证,如有疏漏欢迎在评论区指正。最后更新:2026年07月12日 11:21

赵一鸣

产品评测编辑

前产品经理,现专注 AI 工具评测。实测过 30+ 款 AI 产品,擅长横向对比和用户体验分析。

读者评论 5

运营小陈 1周前
转发到团队群了,大家都觉得有参考价值。
回复 点赞 (4)
数据分析师 1周前
数据引用很扎实,建议补充一下近三个月的最新数据。
回复 点赞 (9)
产品经理阿杰 2周前
从产品角度看,这个方向确实有机会,但商业化路径还需要验证。
回复 点赞 (15)
张工 3天前
写得很实在,特别是实测对比那部分,跟我自己的使用感受一致。
回复 点赞 (12)
前端工程师 6天前
代码示例很清晰,直接用到项目里了。
回复 点赞 (6)