关于 graphql
graphql 是使用 Node.js 和 Apollo Server 构建 GraphQL API 的学习 Skill,涵盖 Schema 设计、解析器、数据访问、安全、订阅、性能和测试,从入门概念延伸到进阶主题。
主要功能
- 01GraphQL Schema 与解析器指导
- 02Apollo Server 配置示例
- 03使用 DataLoader 缓解 N+1 问题
- 04身份验证与授权模式
- 05订阅与 Federation 主题
- 06测试和错误处理示例
适用场景
- 01学习构建 GraphQL API
- 02添加实时订阅
- 03减少 N+1 数据获取问题
- 04测试 GraphQL 查询与变更
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ pluginagentmarketplace/ custom-plugin-nodejs --skill graphql安装后在 Claude Code 中输入/graphql确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/config.yamlschema.jsonreferences/GUIDE.mdPATTERNS.mdscripts/validate.py详细介绍
使用 Node.js 开发 GraphQL 的技能
掌握如何使用 Node.js、Apollo Server、类型安全的架构和实时订阅来构建灵活、高效的 GraphQL API。
快速入门
分 4 步构建 GraphQL API:
- 定义架构 - 类型、查询、变更
- 编写解析器 - 数据获取逻辑
- 设置服务 - Apollo Server 配置
- 连接数据 - 数据库集成
核心概念
架构定义语言(SDL)
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String
author: User!
}
type Query {
user(id: ID!): User
users(limit: Int, offset: Int): [User!]!
post(id: ID!): Post
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User
deleteUser(id: ID!): Boolean!
}
input CreateUserInput {
name: String!
email: String!
password: String!
}
type Subscription {
postCreated: Post!
}
Apollo Server 设置
const { ApolloServer } = require('@apollo/server');
const { expressMiddleware } = require('@apollo/server/express4');
const { readFileSync } = require('fs');
const typeDefs = readFileSync('./schema.graphql', 'utf-8');
const resolvers = {
Query: {
user: async (_, { id }, { dataSources }) => {
return dataSources.userAPI.getUser(id);
},
users: async (_, { limit = 10, offset = 0 }, { dataSources }) => {
return dataSources.userAPI.getUsers(limit, offset);
}
},
Mutation: {
createUser: async (_, { input }, { dataSources }) => {
return dataSources.userAPI.createUser(input);
}
},
User: {
posts: async (parent, _, { dataSources }) => {
return dataSources.postAPI.getPostsByAuthor(parent.id);
}
}
};
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
app.use('/graphql', express.json(), expressMiddleware(server, {
context: async ({ req }) => ({
user: req.user,
dataSources: {
userAPI: new UserAPI(),
postAPI: new PostAPI()
}
})
}));
学习路径
初级(2-3 周)
- ✅ 理解 GraphQL 概念
- ✅ 使用 SDL 定义架构
- ✅ 编写基础解析器
- ✅ 查询和变更基础
中级(4-6 周)
- ✅ 字段解析器和关系
- ✅ 输入验证
- ✅ 错误处理
- ✅ 使用 DataLoader 解决 N+1 问题
高级(8-10 周)
- ✅ 订阅(实时)
- ✅ 身份验证和授权
- ✅ 用于微服务的联邦
- ✅ 性能优化
使用 DataLoader 解决 N+1 问题
const DataLoader = require('dataloader');
const createUserLoader = () =>
new DataLoader(async (userIds) => {
const users = await User.find({ _id: { $in: userIds } });
const userMap = new Map(users.map(u => [u.id, u]));
return userIds.map(id => userMap.get(id));
});
// Use in resolver
User: {
posts: (parent, _, { loaders }) => {
return loaders.userLoader.load(parent.authorId);
}
}
身份验证与授权
const { shield, rule, allow } = require('graphql-shield');
const isAuthenticated = rule()((parent, args, { user }) => {
return user !== null;
});
const isAdmin = rule()((parent, args, { user }) => {
return user?.role === 'admin';
});
const permissions = shield({
Query: { '*': allow, users: isAuthenticated },
Mutation: {
createPost: isAuthenticated,
deleteUser: isAdmin
}
});
错误处理
const { ApolloError, UserInputError } = require('apollo-server-express');
class NotFoundError extends ApolloError {
constructor(message) {
super(message, 'NOT_FOUND');
}
}
// In resolvers
const resolvers = {
Query: {
user: async (_, { id }) => {
const user = await User.findById(id);
if (!user) throw new NotFoundError(`User ${id} not found`);
return user;
}
}
};
单元测试模板
const { createTestClient } = require('apollo-server-testing');
describe('GraphQL API', () => {
let query, mutate;
beforeAll(() => {
const server = new ApolloServer({ typeDefs, resolvers });
const testClient = createTestClient(server);
query = testClient.query;
mutate = testClient.mutate;
});
it('should return users list', async () => {
const GET_USERS = `query { users { id name } }`;
const res = await query({ query: GET_USERS });
expect(res.errors).toBeUndefined();
expect(res.data.users).toBeDefined();
});
});
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
| N+1 查询问题 | 字段解析器 | 使用 DataLoader |
| 查询缓慢 | 未缓存 | 实现 Apollo Cache |
| 类型错误 | 架构不匹配 | 使用 codegen 验证 |
| 绕过身份验证 | 缺少防护机制 | 使用 graphql-shield |
适用场景
以下情况适合使用 GraphQL:
- 客户端需要灵活获取数据
- 多个客户端有不同的数据需求
- 避免过度获取/获取不足
- 需要实时更新
- 无需版本控制即可演进 API
相关技能
- Express REST API(替代方案)
- 数据库集成(数据源)
- JWT 身份验证(保护 API)
资源
评论
支持 Markdown