用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/microwind/ai-skills --skill graphql-api命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | GraphQL API开发 |
| description | 当开发GraphQL API时,分析查询策略,优化API性能,解决数据获取问题。验证GraphQL架构,设计查询模式,和最佳实践。 |
| license | MIT |
GraphQL是一种现代化的API查询语言,提供了比REST更灵活的数据获取方式。不当的GraphQL设计会导致性能问题、安全漏洞和复杂性增加。需要建立完善的GraphQL开发规范。
核心原则: 好的GraphQL设计应该高效、安全、易于维护。坏的GraphQL设计会导致N+1查询问题、性能下降和安全风险。
始终:
触发短语:
问题:
查询列表时,每个项目都触发额外的数据库查询
后果:
- 数据库压力大
- 响应时间长
- 性能线性下降
- 服务器资源浪费
解决方案:
- 数据加载器(DataLoader)
- 批量查询优化
- 预加载关联数据
- 查询合并策略
问题:
客户端发送过于复杂的嵌套查询
后果:
- 服务器性能下降
- 内存占用过高
- 响应超时
- 拒绝服务攻击风险
解决方案:
- 查询深度限制
- 复杂度分析
- 查询超时设置
- 白名单字段限制
问题:
Schema设计过于复杂或不一致
后果:
- 开发困难
- 维护成本高
- 客户端困惑
- 版本管理困难
解决方案:
- 简化Schema设计
- 统一命名规范
- 模块化设计
- 版本控制策略
# 用户类型
type User {
id: ID!
username: String!
email: String!
profile: Profile
posts: [Post!]!
createdAt: DateTime!
}
# 用户资料类型
type Profile {
id: ID!
firstName: String!
lastName: String!
avatar: String
bio: String
}
# 文章类型
type Post {
id: ID!
title: String!
content: String!
author: User!
comments Comment
String
DateTime
user ID User
users Int, Int User
post ID Post
posts Int, Int Post
search String SearchResult
createUser CreateUserInput User
updateUser ID, UpdateUserInput User
createPost CreatePostInput Post
deletePost ID Boolean
Post
userUpdated ID User
CreateUserInput
String
String
String
ProfileInput
ProfileInput
String
String
String
String
SearchResult User Post Comment
UserRole
ADMIN
MODERATOR
USER
DateTime
Upload
# 可评论接口
interface Commentable {
id: ID!
comments: [Comment!]!
}
# 实现接口
type Post implements Commentable {
id: ID!
title: String!
content: String!
comments: [Comment!]!
}
type Video implements Commentable {
id: ID!
title: String!
url: String!
duration: Int!
comments: [Comment!]!
}
import graphene
from graphene_django import DjangoObjectType
from django.contrib.auth.models import User
from datetime import datetime
import promise
class ProfileType(graphene.ObjectType):
id = graphene.ID()
first_name = graphene.String()
last_name = graphene.String()
avatar = graphene.String()
bio = graphene.String()
class UserType(DjangoObjectType):
profile = graphene.Field(ProfileType)
posts = graphene.List('PostType')
class Meta:
model = User
fields = ('id', 'username', 'email', 'date_joined')
def resolve_profile(self, info):
if hasattr(self, 'profile'):
return self.profile
return None
def resolve_posts(self, info):
# 使用DataLoader解决N+1问题
return info.context.loaders.post_loader.load(self.id)
class PostType(graphene.ObjectType):
id = graphene.ID()
title = graphene.String()
content = graphene.String()
author = graphene.Field(UserType)
comments = graphene.()
tags = graphene.(graphene.String)
created_at = graphene.DateTime()
():
info.context.loaders.user_loader.load(.author_id)
():
info.context.loaders.comment_loader.load(.)
(graphene.ObjectType):
user = graphene.Field(UserType, =graphene.ID(required=))
users = graphene.(UserType, limit=graphene.Int(), offset=graphene.Int())
post = graphene.Field(PostType, =graphene.ID(required=))
posts = graphene.(PostType, limit=graphene.Int(), offset=graphene.Int())
():
info.context.loaders.user_loader.load(())
():
queryset = User.objects.()
offset:
queryset = queryset[offset:]
limit:
queryset = queryset[:limit]
queryset
():
info.context.loaders.post_loader.load(())
():
queryset = Post.objects.()
offset:
queryset = queryset[offset:]
limit:
queryset = queryset[:limit]
queryset
(graphene.Mutation):
user = graphene.Field(UserType)
success = graphene.Boolean()
errors = graphene.(graphene.String)
:
username = graphene.String(required=)
email = graphene.String(required=)
password = graphene.String(required=)
first_name = graphene.String()
last_name = graphene.String()
():
:
user = User.objects.create_user(
username=username,
email=email,
password=password
)
first_name last_name:
Profile.objects.create(
user=user,
first_name=first_name,
last_name=last_name
)
CreateUser(user=user, success=, errors=[])
Exception e:
CreateUser(user=, success=, errors=[(e)])
(graphene.ObjectType):
create_user = CreateUser.Field()
promise Promise
promise.dataloader DataLoader
():
():
users = User.objects.(id__in=keys)
user_dict = {user.: user user users}
Promise.resolve([user_dict.get(key) key keys])
():
():
posts = Post.objects.(author_id__in=keys)
posts_dict = {}
post posts:
posts_dict.setdefault(post.author_id, []).append(post)
Promise.resolve([posts_dict.get(key, []) key keys])
graphql.validation.rules QueryComplexityRule
graphql GraphQLSchema, validate
:
():
.max_complexity = max_complexity
():
complexity =
():
complexity
(node, ):
selection node.selection_set.selections:
complexity +=
calculate_complexity(selection)
:
graphql
ast = graphql.parse(query)
calculate_complexity(ast)
Exception:
complexity <= .max_complexity
django.views.decorators.csrf csrf_exempt
django.http JsonResponse
json
():
request.method == :
JsonResponse({: })
request.method == :
:
data = json.loads(request.body)
query = data.get()
variables = data.get(, {})
complexity_limiter = QueryComplexityLimiter(max_complexity=)
complexity_limiter.analyze_query(query, schema):
JsonResponse({
: [{: }]
}, status=)
loaders = {
: UserLoader(),
: PostLoader(),
: CommentLoader()
}
context = {: loaders}
result = schema.execute(query, variables=variables, context=context)
JsonResponse({
: result.data,
: [(error) error result.errors] result.errors
})
Exception e:
JsonResponse({
: [{: (e)}]
}, status=)
schema = graphene.Schema(query=Query, mutation=Mutation)
import { ApolloClient, InMemoryCache, gql, createHttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
// HTTP链接
const httpLink = createHttpLink({
uri: 'http://localhost:8000/graphql/',
});
// 认证链接
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem('authToken');
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
}
}
});
// Apollo客户端
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
defaultOptions: {
watchQuery: {
errorPolicy: 'all',
},
query: {
errorPolicy: 'all',
},
},
});
// GraphQL查询
const GET_USER = gql`
query GetUser(: ID
user )
id
username
email
profile
firstName
lastName
avatar
posts
id
title
content
createdAt
`;
= gql`;
= gql`;
= () => {
{
response = client.({
: ,
: { id },
});
response..;
} (error) {
.(, error);
error;
}
};
= () => {
{
response = client.({
: ,
variables,
});
response..;
} (error) {
.(, error);
error;
}
};
= () => {
{
response = client.({
: ,
: { input },
});
response..;
} (error) {
.(, error);
error;
}
};
{ useQuery, useMutation } ;
= () => {
{ loading, error, data } = (, {
: { id },
: !id,
});
{
: data?.,
loading,
error,
};
};
= () => {
[createUserMutation, { loading, error }] = (, {
: {
cache.({
: {
: [...existing, createUser]
}
});
},
});
= () => {
result = ({
: { input },
});
result..;
};
{
createUser,
loading,
error,
};
};
= () => {
[page, setPage] = ();
[users, setUsers] = ([]);
{ loading, error, data, fetchMore } = (, {
: {
: pageSize,
: page * pageSize,
},
});
( {
(data?.) {
(page === ) {
(data.);
} {
( [...prev, ...data.]);
}
}
}, [data, page]);
= () => {
(!loading && data?.?. === pageSize) {
( prev + );
}
};
{
users,
loading,
error,
loadMore,
: data?.?. === pageSize,
};
};