用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/pluginagentmarketplace/custom-plugin-api-design --skill graphql命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | graphql |
| version | 2.0.0 |
| description | GraphQL API design and schema development |
| sasmp_version | 1.3.0 |
| bonded_agent | 01-api-architect |
| bond_type | PRIMARY_BOND |
| atomic_design | {"single_responsibility":"GraphQL schema design and resolver patterns","boundaries":{"includes":["schema_design","resolvers","subscriptions","n_plus_one","caching"],"excludes":["rest_design","database_queries","frontend_code"]}} |
| parameter_validation | {"schema":{"type":"object","properties":{"operation_type":{"type":"string","enum":["query","mutation","subscription"]},"complexity_limit":{"type":"number","minimum":0,"maximum":1000}}}} |
| retry_config | {"enabled":true,"max_attempts":3,"backoff":{"type":"exponential","initial_delay_ms":1000,"max_delay_ms":30000}} |
| logging | {"level":"INFO","fields":["operation_name","complexity","duration_ms"]} |
| dependencies | {"skills":["api-architecture"],"agents":["01-api-architect"]} |
Design efficient GraphQL APIs with proper schema patterns.
# Scalar types
scalar DateTime
scalar UUID
scalar Email
# Object type
type User {
id: ID!
email: Email!
name: String!
status: UserStatus!
profile: Profile
teams: [Team!]!
createdAt: DateTime!
updatedAt: DateTime
}
# Enum
enum UserStatus {
ACTIVE
INACTIVE
BANNED
}
# Interface
interface Node {
id: ID!
}
# Union
union SearchResult = User | Team | Post
type
user ID User
users
Int
String
Int
String
UserFilter
UserConnection
search String, SearchType SearchResult
UserFilter
UserStatus
String
DateTime
type Mutation {
# Create
createUser(input: CreateUserInput!): CreateUserPayload!
# Update
updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
# Delete
deleteUser(id: ID!): DeleteUserPayload!
# Action
verifyUser(id: ID!): VerifyUserPayload!
}
# Input types
input CreateUserInput {
email: Email!
name: String!
password: String!
}
input UpdateUserInput {
name: String
status: UserStatus
}
# Payload types (with errors)
type CreateUserPayload {
user: User
errors: [UserError!]!
}
type UserError {
field: String
message: String!
code: ErrorCode!
}
type Subscription {
# Real-time updates
userCreated: User!
userUpdated(id: ID): User!
# Filtered subscription
orderStatusChanged(orderId: ID!): Order!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
const resolvers = {
Query: {
user: async (_, { id }, context) => {
return context.dataSources.users.findById(id);
},
users: async (_, { first, after, filter }, context) => {
return context.dataSources.users.findMany({
first,
after,
filter,
});
},
},
User: {
// Field resolver
teams: async (user, _, context) => {
return context.dataSources.teams.findByUserId(user.id);
},
},
};
import DataLoader from 'dataloader';
// Create loader
const userLoader = new DataLoader(async (ids: string[]) => {
const users = await db.query(
'SELECT * FROM users WHERE id = ANY($1)',
[ids]
);
// Return in same order as input ids
const userMap = new Map(users.map(u => [u.id, u]));
return ids.map(id => userMap.get(id) || null);
});
// Use in resolver
const resolvers = {
Post: {
author: (post, _, context) => {
return context.loaders.user.load(post.authorId);
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => ({
user: req.user,
loaders: {
user: new DataLoader(batchUsers),
team: new DataLoader(batchTeams),
},
dataSources: {
users: new UserDataSource(db),
teams: new TeamDataSource(db),
},
}),
});
import { GraphQLError } from 'graphql';
// Custom error
throw new GraphQLError('User not found', {
extensions: {
code: 'NOT_FOUND',
field: 'userId',
},
});
// Error formatting
const server = new ApolloServer({
formatError: (error) => {
// Log internal errors
if (error.extensions?.code === 'INTERNAL_SERVER_ERROR') {
logger.error(error);
return { message: 'Internal server error' };
}
return error;
},
});
import { createComplexityRule } from 'graphql-query-complexity';
const complexityRule = createComplexityRule({
maximumComplexity: 1000,
estimators: [
fieldExtensionsEstimator(),
simpleEstimator({ defaultComplexity: 1 }),
],
onComplete: (complexity) => {
console.log('Query complexity:', complexity);
},
});
const server = new ApolloServer({
validationRules: [complexityRule],
});
import depthLimit from 'graphql-depth-limit';
const server = new ApolloServer({
validationRules: [depthLimit(10)],
});
import { describe, it, expect } from 'vitest';
import { ApolloServer } from '@apollo/server';
import { typeDefs, resolvers } from './schema';
describe('GraphQL API', () => {
const server = new ApolloServer({ typeDefs, resolvers });
describe('Query.user', () => {
it('should return user by id', async () => {
const result = await server.executeOperation({
query: `
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`,
variables: { id: 'user-123' },
});
expect(result.body.singleResult.data?.user).toEqual({
id: 'user-123',
name: 'John Doe',
email: 'john@example.com',
});
});
it('should return null for non-existent user', async () => {
const result = await server.executeOperation({
query: `query { user(id: "invalid") { id } }`,
});
expect(result.body.singleResult.data?.user).toBeNull();
});
});
describe('Mutation.createUser', () => {
it('should create user and return payload', async () => {
const result = await server.executeOperation({
query: `
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
user { id name }
errors { field message }
}
}
`,
variables: {
input: { email: 'new@example.com', name: 'New User', password: 'Secret123!' },
},
});
expect(result.body.singleResult.data?.createUser.user).toBeDefined();
expect(result.body.singleResult.data?.createUser.errors).toEqual([]);
});
});
});
| Issue | Cause | Solution |
|---|---|---|
| N+1 queries | Field-level resolvers | Use DataLoader |
| Slow queries | High complexity | Add complexity limits |
| Memory issues | Large result sets | Implement pagination |
| Introspection leak | Enabled in production | Disable in prod |