GraphQL 的核心是 Schema,Claude Code 在 Schema 设计和 Resolver 实现阶段 都能显著加速——让你专注业务逻辑而不是模板代码。
SDL 优先:让 Claude 从需求生成 Schema
你:我需要一个博客系统的 GraphQL API,功能包括:
用户(注册/登录/个人资料)、
文章(发布/编辑/删除/按标签筛选)、
评论(添加/嵌套回复/点赞)、
标签(文章可以有多个标签)
用 Schema-First 方式设计,注意:
- 用 Relay 风格的分页(Connection/Edge/PageInfo)
- 区分 Query(查询)/ Mutation(变更)/ Subscription(订阅)
- 加上字段描述注释
Claude:生成完整 SDL:
type Query {
me: User
post(id: ID!): Post
posts(filter: PostFilter, first: Int, after: String): PostConnection!
tags: [Tag!]!
}
type Mutation {
register(input: RegisterInput!): AuthPayload!
login(input: LoginInput!): AuthPayload!
createPost(input: CreatePostInput!): Post!
updatePost(id: ID!, input: UpdatePostInput!): Post!
deletePost(id: ID!): Boolean!
addComment(postId: ID!, input: CommentInput!): Comment!
likeComment(commentId: ID!): Comment!
}
type Subscription {
commentAdded(postId: ID!): Comment!
}
type User {
id: ID!
username: String!
email: String!
posts(first: Int, after: String): PostConnection!
createdAt: DateTime!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
tags: [Tag!]!
comments(first: Int, after: String): CommentConnection!
likesCount: Int!
createdAt: DateTime!
updatedAt: DateTime!
}
type PostConnection {
edges: [PostEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type PostEdge {
node: Post!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
DataLoader 解决 N+1 问题
GraphQL 最常见的性能陷阱是 N+1 查询。让 Claude 帮你识别并修复:
你:这是我的 User Resolver:
const resolvers = {
Post: {
author: async (post) => {
return await db.user.findUnique({ where: { id: post.authorId } });
}
}
}
查询 100 篇文章时,author 字段会触发 100 次数据库查询。
帮我用 DataLoader 优化。
Claude:
import DataLoader from 'dataloader';
// 创建 DataLoader(每个请求生命周期内共享)
function createUserLoader() {
return new DataLoader<string, User>(async (userIds) => {
// 一次批量查询
const users = await db.user.findMany({
where: { id: { in: userIds as string[] } }
});
// 按原始 ID 顺序返回(DataLoader 要求)
const userMap = new Map(users.map(u => [u.id, u]));
return userIds.map(id => userMap.get(id) ?? new Error(`User ${id} not found`));
});
}
// 在 Apollo Server context 中注入
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => ({
userId: getUserFromToken(req),
loaders: {
user: createUserLoader(), // 每次请求创建新实例
}
})
});
// Resolver 改用 DataLoader
const resolvers = {
Post: {
author: (post, _, { loaders }) => {
return loaders.user.load(post.authorId); // 自动批量
}
}
}
字段级权限控制
你:帮我实现字段级访问控制:
- User.email 只有本人和管理员能看
- Post.content 草稿状态只有作者能看
- 其他字段所有人可见
Claude:
import { shield, rule, and } from 'graphql-shield';
const isAuthenticated = rule()(async (parent, args, ctx) => {
return !!ctx.userId;
});
const isOwner = rule()(async (parent, args, ctx) => {
return parent.authorId === ctx.userId || parent.id === ctx.userId;
});
const isAdmin = rule()(async (parent, args, ctx) => {
const user = await ctx.loaders.user.load(ctx.userId);
return user?.role === 'ADMIN';
});
export const permissions = shield({
User: {
email: and(isAuthenticated, isOwner), // 只有本人
},
Post: {
content: rule()(async (post, args, ctx) => {
if (post.status !== 'DRAFT') return true;
return post.authorId === ctx.userId; // 草稿只有作者能看
}),
},
});
Subscription 实时通知
typescript
// 评论订阅(使用 graphql-ws)
const resolvers = {
Subscription: {
commentAdded: {
subscribe: (_, { postId }, { pubsub }) => {
return pubsub.asyncIterableIterator(`COMMENT_ADDED_${postId}`);
},
resolve: (payload) => payload.comment,
},
},
Mutation: {
addComment: async (_, { postId, input }, { db, pubsub, userId }) => {
const comment = await db.comment.create({
data: { ...input, postId, authorId: userId }
});
// 发布事件,所有订阅了该帖子的客户端都会收到
await pubsub.publish(`COMMENT_ADDED_${postId}`, { comment });
return comment;
}
}
};GraphQL Code Generator 类型生成
yaml
# codegen.yml
schema: src/schema.graphql
generates:
src/generated/graphql.ts:
plugins:
- typescript
- typescript-resolvers
config:
contextType: '../context#Context'
useIndexSignature: truebash
# 让 Claude 帮你写 codegen 配置
claude "根据我的 schema.graphql,生成 codegen.yml 配置,
要生成 TypeScript 类型 + Resolver 类型 + React Query hooks"
# 运行生成
npx graphql-codegen从 REST 渐进迁移到 GraphQL
迁移策略(不要一次全改):
Phase 1:并行运行
- GraphQL 端点 /graphql 提供新功能
- 旧 REST 端点继续工作
- 新前端功能优先用 GraphQL
Phase 2:GraphQL 包装 REST(BFF 模式)
- GraphQL Resolver 内部调用现有 REST API
- 前端全量切换到 GraphQL
- 不改后端业务逻辑
Phase 3:替换底层实现
- Resolver 直接查数据库(绕过 REST)
- 逐步废弃旧 REST 端点
来源:Claude Code 官方文档 - docs.anthropic.com/en/docs/claude-code