Skip to main content Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/pluginagentmarketplace/custom-plugin-api-design --skill graphqlThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... More from this repository Related occupations SOC
Based on SOC occupation classification
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"]}
GraphQL API Design Skill
Purpose
Design efficient GraphQL APIs with proper schema patterns.
Schema Design
Types
scalar DateTime
scalar UUID
scalar Email
type User {
id : ID!
email : Email!
name : String!
status : UserStatus!
profile : Profile
teams : [ Team! ] !
createdAt : DateTime!
updatedAt : DateTime
}
enum UserStatus {
ACTIVE
INACTIVE
BANNED
}
interface Node {
id : ID!
}
union SearchResult = User | Team | Post
Queries
type
user ID User
users
Int
String
Int
String
UserFilter
UserConnection
search String , SearchType SearchResult
UserFilter
UserStatus
String
DateTime
Query
{
(
id
:
!
)
:
(
first
:
after
:
last
:
before
:
filter
:
)
:
!
(
query
:
!
types
:
[
!
]
)
:
[
!
]
!
}
input
{
status
:
role
:
createdAfter
:
}
Mutations type Mutation {
createUser( input : CreateUserInput! ) : CreateUserPayload!
updateUser( id : ID! , input : UpdateUserInput! ) : UpdateUserPayload!
deleteUser( id : ID! ) : DeleteUserPayload!
verifyUser( id : ID! ) : VerifyUserPayload!
}
input CreateUserInput {
email : Email!
name : String!
password : String!
}
input UpdateUserInput {
name : String
status : UserStatus
}
type CreateUserPayload {
user : User
errors : [ UserError! ] !
}
type UserError {
field : String
message : String!
code : ErrorCode!
}
Subscriptions type Subscription {
userCreated : User!
userUpdated( id : ID) : User!
orderStatusChanged( orderId : ID! ) : Order!
}
Connection Pattern (Relay) type UserConnection {
edges : [ UserEdge! ] !
pageInfo : PageInfo!
totalCount : Int!
}
type UserEdge {
node : User!
cursor : String!
}
type PageInfo {
hasNextPage : Boolean!
hasPreviousPage : Boolean!
startCursor : String
endCursor : String
}
Resolver Patterns
Basic Resolver 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 : {
teams : async (user, _, context) => {
return context.dataSources .teams .findByUserId (user.id );
},
},
};
DataLoader (N+1 Solution) import DataLoader from 'dataloader' ;
const userLoader = new DataLoader (async (ids : string []) => {
const users = await db.query (
'SELECT * FROM users WHERE id = ANY($1)' ,
[ids]
);
const userMap = new Map (users.map (u => [u.id , u]));
return ids.map (id => userMap.get (id) || null );
});
const resolvers = {
Post : {
author : (post, _, context ) => {
return context.loaders .user .load (post.authorId );
},
},
};
Context Setup 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),
},
}),
});
Error Handling import { GraphQLError } from 'graphql' ;
throw new GraphQLError ('User not found' , {
extensions : {
code : 'NOT_FOUND' ,
field : 'userId' ,
},
});
const server = new ApolloServer ({
formatError : (error ) => {
if (error.extensions ?.code === 'INTERNAL_SERVER_ERROR' ) {
logger.error (error);
return { message : 'Internal server error' };
}
return error;
},
});
Security
Query Complexity 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],
});
Depth Limiting import depthLimit from 'graphql-depth-limit' ;
const server = new ApolloServer ({
validationRules : [depthLimit (10 )],
});
Unit Test Template 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 ([]);
});
});
});
Troubleshooting 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
Quality Checklist