用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/ffsshhttiikk/opencode-agents-skills --skill graphql命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | graphql |
| description | GraphQL API design best practices and patterns |
| license | MIT |
| compatibility | opencode |
| metadata | {"audience":"developers","category":"api-design"} |
When implementing or querying GraphQL APIs.
scalar DateTime
scalar UUID
scalar Email
scalar URL
interface Node {
id: ID!
}
interface Error {
message: String!
code: String!
}
type User implements Node {
id: ID!
email: Email!
username: String!
name: String
avatarUrl: URL
posts(first: Int, after: Cursor): PostConnection!
createdAt: DateTime!
}
type Post implements Node {
id: ID!
title: String!
slug: String!
excerpt: String
content: String!
author: User!
tags: [Tag!]!
publishedAt: DateTime
createdAt: DateTime!
updatedAt: DateTime!
}
type Tag implements Node {
id: ID!
name: String!
slug: String!
postCount: Int!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: Cursor
endCursor: Cursor
}
type PostConnection {
edges: [PostEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type PostEdge {
node: Post!
cursor: Cursor!
}
input CreatePostInput {
title: String!
content: String!
tags: [String!]
}
type Mutation {
createPost(input: CreatePostInput!): Post!
deletePost(id: ID!): Boolean!
publishPost(id: ID!): Post!
}
type Query {
node(id: ID!): Node
user(id: ID!): User
users(first: Int, after: Cursor): UserConnection!
post(slug: String!): Post
posts(
author: ID
tag: String
first: Int
after: Cursor
): PostConnection!
}
type Subscription {
postPublished(tag: String): Post!
}
from dataloader import DataLoader
class UserLoader(DataLoader):
def batch_load_fn(self, keys):
users = user_repository.find_by_ids(keys)
return [users.get(key) for key in keys]
class PostLoader(DataLoader):
def batch_load_fn(self, keys):
posts = post_repository.find_by_author_ids(keys)
return [posts.get(key) for key in keys]
# In resolvers
def resolve_user_posts(user, info, first=10, after=None):
loader = info.context.user_loader
return loader.load(user.id).then(
lambda user: connection_from_list_slice(
user.posts[:first],
loaders=loader,
slice_start=0,
list_length=len(user.posts),
list_slice_length=first,
)
)
# Context setup
def get_context(request):
return {
'user_loader': UserLoader(),
'post_loader': PostLoader(),
'current_user': get_current_user(request),
}
from graphql import parse, FieldNode
def get_query_depth(query):
def traverse(node, depth):
if isinstance(node, FieldNode):
return max(
(traverse(child, depth + 1) for child in node.selection_set.selections),
default=depth
)
return depth
return traverse(query, 0)
def complexity_validation(schema):
def validate(ast):
query = parse(ast.query_string)
depth = get_query_depth(query)
if depth > 10:
raise GraphQLError("Query too deep")
return depth
return validate
# Limit number of items in lists
LIMIT = 100
def enforce_list_limits(args):
first = args.get('first', 0)
args['first'] = min(first, LIMIT) if first else LIMIT
return args
type Mutation {
createPost(input: CreatePostInput!): CreatePostResult!
}
union CreatePostResult = Post | ValidationError | UnauthorizedError
type ValidationError implements Error {
message: String!
code: String!
fields: [FieldError!]!
}
type FieldError {
field: String!
message: String!
}
# Python implementation
def resolve_create_post(_, info, input):
try:
validate_input(input)
post = post_service.create(input, author=info.context.current_user)
return post
except ValidationError as
return ValidationError
messagestre,
code,
fieldse.errors
except UnauthorizedError as
return UnauthorizedError
messagestre,
code