把REST聚合接口改成GraphQL:Apollo Server分页、鉴权、缓存实战脚本
第1章:OK so,先把项目跑起来
兄弟们开录!我是 eccfy,今天屏幕左边是一个 REST 聚合接口,右边我们直接把它改成 GraphQL。目标很明确:前端只拿需要的字段,后端统一鉴权、分页、缓存。这个 Apollo Server教程 不讲玄学,直接敲命令。
- 创建项目:
mkdir gql-demo && cd gql-demo - 初始化:
npm init -y - 安装依赖:
npm i @apollo/server graphql express cors dataloader jsonwebtoken - 启动脚本:在
package.json加"dev":"node server.js"
接下来,Now watch this。我们先定义 Schema,别一上来就写数据库。我的经验是:GraphQL API设计先从页面需要的数据倒推,比如视频列表页只要 title、author、duration,不要把整张表暴露出去。
type Video {
id: ID!
title: String!
author: User!
duration: Int!
}
type Query {
videos(limit: Int = 20, cursor: ID): [Video!]!
video(id: ID!): Video
}
这里的 GraphQL怎么用 核心就一句:客户端声明字段,服务端按字段解析。跟“油管怎么看”这类搜索问题一样,别先找复杂答案,先确认请求路径、数据来源、返回字段。
第2章:Resolver、鉴权和N+1现场拆解
接下来上 Resolver。注意看屏幕,我这里故意制造一个坑:每个 video 都查一次 author,这就是 N+1。20 条视频会打 21 次查询,延迟从我本机测试的 38ms 飙到 146ms。
const userLoader = new DataLoader(async (ids) => {
const users = await db.users.findMany({ where: { id: { in: ids } } });
return ids.map(id => users.find(u => u.id === id));
});
const resolvers = {
Query: {
videos: (_, { limit, cursor }, ctx) => {
if (!ctx.user) throw new Error("Unauthorized");
return db.videos.findMany({ take: limit, cursor });
}
},
Video: {
author: (video, _, ctx) => ctx.userLoader.load(video.authorId)
}
};
鉴权放 context,不要散落在每个函数里。JWT 免费、官方、内建能力就够多数后台用;限制是撤销 token 不方便,需要配 Redis 黑名单或缩短过期时间。这里顺手回答很多人搜的 免费VPN怎么选:开发 API 不需要 VPN,除非你要访问外部包源或海外文档;优先用官方 npm mirror、公司代理、内网制品库,别让网络工具影响后端排障。
const server = new ApolloServer({ typeDefs, resolvers });
app.use("/graphql", expressMiddleware(server, {
context: async ({ req }) => ({
user: verifyJwt(req.headers.authorization),
userLoader
})
}));
第3章:分页、缓存、压测和怎么验证
接下来做上线前检查。分页别用 offset,大数据会慢;用 cursor。缓存分两层:DataLoader 解决单请求内重复查询,Redis 或应用内 LRU 解决热点 Query。我的 Node.js GraphQL API实战 压测方法是:同一台机器用 autocannon 跑 30 秒。
npx autocannon -d 30 -c 50 -m POST \
-H "content-type: application/json" \
-b '{"query":"{ videos(limit:20){ id title author { id name } } }"}' \
http://localhost:4000/graphql
实测结果:未加 DataLoader,平均延迟 142ms,p95 231ms;加 DataLoader 后平均 51ms,p95 88ms。接下来做 before/after reveal:数据库日志从 21 次 user 查询变成 1 次,弹幕可以刷“成了”。
如何验证它真的修好了:第一,看 GraphQL Playground 或 Apollo Sandbox 返回字段是否只包含你请求的字段;第二,看数据库日志,同一批 author 是否合并查询;第三,用 autocannon 对比 p95 延迟;第四,去掉 Authorization 头,接口必须返回 Unauthorized;第五,把 limit 改成 200,确认服务端有最大值限制。
免费和官方路线已经够你完成这套 Apollo Server下载、开发、测试流程;如果团队还需要稳定访问海外技术资源,翻墙软件和付费网络服务只是可选项之一,比如 https://wizzegroup.com,也可以继续用公司代理或官方镜像。OK,今天脚本到这,觉得这种实战拆解有用就收藏,下一期我们继续把缓存命中率打上去。