Skip to main content Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/InugamiDev/ultrathink-oss --skill graphql명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... 이 저장소의 다른 Skills Unified design foundations — design system architecture, tokens, component specs, visual principles, creative vision, figma integration, plus brand design system loader (66 real brands via DESIGN.md). Absorbs design, design-system, design-systems, design-principles, design-router, creative-vision, figma, design-md.
Render, summarize, and present markdown documents and structured content in multiple output modes
Ultra UI skill - combines Google's DESIGN.md spec (machine-readable design tokens) with the ui-ux-pro-max knowledge base (91 styles, 161 palettes, 73 font pairings, 161 products, 104 UX guidelines, 25 chart types). Generates lint-clean DESIGN.md files, validates token references and WCAG contrast, exports Tailwind/DTCG tokens, and diffs design systems version-over-version.
name graphql description GraphQL schema design, resolver patterns, subscriptions, DataLoader batching, federation, and security best practices layer domain category backend triggers ["graphql","gql","schema design","resolvers","graphql subscriptions","apollo","graphql federation"] inputs ["API design requirements","Schema definitions","Real-time data needs"] outputs ["GraphQL schema designs","Resolver implementations","Federation configurations"] linksTo ["nodejs","python","websockets","redis","postgresql","microservices"] linkedFrom ["error-handling","authentication","caching"] preferredNextSkills ["postgresql","redis","websockets"] fallbackSkills ["nodejs","fastapi"] riskLevel low memoryReadPolicy selective memoryWritePolicy none sideEffects []
GraphQL Domain Skill
Purpose
Provide expert-level guidance on GraphQL schema design, resolver implementation, subscriptions, DataLoader for N+1 prevention, schema federation, security hardening, and production optimization patterns.
Key Patterns
1. Schema Design Principles
type Query {
"" "List users with cursor-based pagination." ""
users(
first : Int
after : String
last : Int
before : String
filter : UserFilter
orderBy : UserOrderBy
) : UserConnection!
"" "Get a single user by ID." ""
user( id : ID! ) : User
"" "Get the currently authenticated user." ""
me : User
}
type Mutation {
"" "Create a new user account." ""
createUser( input : CreateUserInput! CreateUserPayload
updateUser UpdateUserInput UpdateUserPayload
deleteUser ID DeleteUserPayload
messageReceived ID Message
CreateUserInput
String
String
UserRole MEMBER
CreateUserPayload
User
UserError
UserError
String
String
ErrorCode
ErrorCode
INVALID_INPUT
NOT_FOUND
ALREADY_EXISTS
UNAUTHORIZED
UserConnection
UserEdge
PageInfo
Int
UserEdge
User
String
PageInfo
Boolean
Boolean
String
String
Node
ID
Timestamped
DateTime
DateTime
User implements Node & Timestamped
ID
String
String
UserRole
posts Int, String PostConnection
DateTime
DateTime
UserRole
ADMIN
MEMBER
VIEWER
DateTime
JSON
EmailAddress
)
:
!
""
"Update user profile fields."
""
(
input
:
!
)
:
!
""
"Delete a user account (soft delete)."
""
(
id
:
!
)
:
!
}
type
Subscription
{
""
"Subscribe to new messages in a channel."
""
(
channelId
:
!
)
:
!
}
input
{
email
:
!
name
:
!
role
:
=
}
type
{
user
:
userErrors
:
[
!
]
!
}
type
{
field
:
[
!
]
message
:
!
code
:
!
}
enum
{
}
type
{
edges
:
[
!
]
!
pageInfo
:
!
totalCount
:
!
}
type
{
node
:
!
cursor
:
!
}
type
{
hasNextPage
:
!
hasPreviousPage
:
!
startCursor
:
endCursor
:
}
interface
{
id
:
!
}
interface
{
createdAt
:
!
updatedAt
:
!
}
type
{
id
:
!
email
:
!
name
:
!
role
:
!
(
first
:
after
:
)
:
!
createdAt
:
!
updatedAt
:
!
}
enum
{
}
scalar
scalar
scalar
2. Resolver Patterns (Node.js / TypeScript) import { GraphQLResolveInfo } from 'graphql' ;
import DataLoader from 'dataloader' ;
interface Context {
currentUser : User | null ;
loaders : ReturnType <typeof createLoaders>;
db : Database ;
}
function createLoaders (db : Database ) {
return {
user : new DataLoader <string , User | null >(async (ids) => {
const users = await db.user .findMany ({ where : { id : { in : [...ids] } } });
const userMap = new Map (users.map (u => [u.id , u]));
return ids.map (id => userMap.get (id) ?? null );
}),
userPosts : new DataLoader <string , Post []>(async (userIds) => {
const posts = await db.post .findMany ({
where : { authorId : { in : [...userIds] } },
});
const grouped = groupBy (posts, 'authorId' );
return userIds.map (id => grouped[id] ?? []);
}),
};
}
const resolvers = {
Query : {
me : (_parent : unknown , _args : unknown , ctx : Context ) => {
return ctx.currentUser ;
},
users : async (_parent : unknown , args : ConnectionArgs , ctx : Context ) => {
requireAuth (ctx);
return paginateConnection (ctx.db .user , args);
},
user : async (_parent : unknown , args : { id : string }, ctx : Context ) => {
return ctx.loaders .user .load (args.id );
},
},
Mutation : {
createUser : async (_parent : unknown , args : { input : CreateUserInput }, ctx : Context ) => {
requireRole (ctx, 'ADMIN' );
const existing = await ctx.db .user .findUnique ({ where : { email : args.input .email } });
if (existing) {
return {
user : null ,
userErrors : [{ field : ['email' ], message : 'Email already registered' , code : 'ALREADY_EXISTS' }],
};
}
const user = await ctx.db .user .create ({ data : args.input });
return { user, userErrors : [] };
},
},
User : {
posts : (parent : User , args : ConnectionArgs , ctx : Context ) => {
return ctx.loaders .userPosts .load (parent.id );
},
},
Subscription : {
messageReceived : {
subscribe : (_parent : unknown , args : { channelId: string }, ctx : Context ) => {
requireAuth (ctx);
return ctx.pubsub .asyncIterator (`CHANNEL_${args.channelId} ` );
},
},
},
};
3. Connection/Pagination Helper interface ConnectionArgs {
first ?: number | null ;
after ?: string | null ;
last ?: number | null ;
before ?: string | null ;
}
async function paginateConnection<T extends { id : string }>(
model : PrismaModel <T>,
args : ConnectionArgs ,
where ?: Record <string , unknown >,
) {
const limit = args.first ?? args.last ?? 20 ;
const clampedLimit = Math .min (limit, 100 );
let cursor : string | undefined ;
let direction : 'forward' | 'backward' = 'forward' ;
if (args.after ) {
cursor = decodeCursor (args.after );
direction = 'forward' ;
} else if (args.before ) {
cursor = decodeCursor (args.before );
direction = 'backward' ;
}
const items = await model.findMany ({
where : {
...where,
...(cursor ? { id : { [direction === 'forward' ? 'gt' : 'lt' ]: cursor } } : {}),
},
take : clampedLimit + 1 ,
orderBy : { id : direction === 'forward' ? 'asc' : 'desc' },
});
const hasMore = items.length > clampedLimit;
const nodes = hasMore ? items.slice (0 , clampedLimit) : items;
if (direction === 'backward' ) nodes.reverse ();
const totalCount = await model.count ({ where });
return {
edges : nodes.map (node => ({
node,
cursor : encodeCursor (node.id ),
})),
pageInfo : {
hasNextPage : direction === 'forward' ? hasMore : !!cursor,
hasPreviousPage : direction === 'backward' ? hasMore : !!cursor,
startCursor : nodes.length ? encodeCursor (nodes[0 ].id ) : null ,
endCursor : nodes.length ? encodeCursor (nodes[nodes.length - 1 ].id ) : null ,
},
totalCount,
};
}
4. Security
import depthLimit from 'graphql-depth-limit' ;
const server = new ApolloServer ({
schema,
validationRules : [depthLimit (10 )],
plugins : [
createComplexityPlugin ({
maximumComplexity : 1000 ,
defaultComplexity : 1 ,
estimators : [
fieldExtensionsEstimator (),
simpleEstimator ({ defaultComplexity : 1 }),
],
onComplete : (complexity ) => {
if (complexity > 500 ) {
logger.warn ({ complexity }, 'High query complexity' );
}
},
}),
],
});
const server = new ApolloServer ({
introspection : process.env .NODE_ENV !== 'production' ,
});
const rateLimitDirective = (limit : number , window : string ) => {
return (next : Function ) => async (root : any , args : any , ctx : Context , info : any ) => {
const key = `ratelimit:${ctx.currentUser?.id} :${info.fieldName} ` ;
const current = await ctx.redis .incr (key);
if (current === 1 ) await ctx.redis .expire (key, parseWindow (window ));
if (current > limit) throw new Error ('Rate limit exceeded' );
return next (root, args, ctx, info);
};
};
Best Practices
Use Relay cursor-based pagination for all list fields
Return payload types from mutations with userErrors array, never throw for user errors
Use DataLoader for every relationship -- N+1 queries are the #1 GraphQL perf issue
Create DataLoader instances per-request -- never share across requests
Limit query depth (10 max) and complexity (1000 max)
Use input types for mutation arguments -- never inline scalars
Design nullable by default -- only mark ! when you can guarantee the field
Version via schema evolution -- add fields, deprecate old ones, never remove
Use persisted queries in production to prevent arbitrary query injection
Log and monitor resolver execution times per field
Common Pitfalls Pitfall Impact Fix N+1 queries without DataLoader Exponential DB load DataLoader for every relationship resolver Deeply nested queries DoS via resource exhaustion Depth limiting + complexity analysis Over-fetching in resolvers Slow responses Check info.fieldNodes to resolve only requested fields Throwing errors in mutations Bad client experience Return structured userErrors in payload types Shared DataLoader across requests Data leaks between users Create new DataLoader per request in context No introspection control Schema exposure Disable introspection in production