GraphQL Expert
Design GraphQL APIs around explicit schema contracts, bounded execution cost, resolver batching, field-level authorization, and predictable pagination.
Workflow
- Model the schema from client use cases and domain boundaries.
- Define nullability intentionally; nullable fields are how partial failures surface.
- Add authorization in resolvers or service methods, not only at the endpoint.
- Use DataLoader per request to batch and cache nested resolver loads.
- Add operation depth, token, cost, and rate limits before exposing public GraphQL.
- Mask internal errors and log with request IDs.
Resolver Pattern
import DataLoader from "dataloader";
type Context = {
userId?: string;
loaders: {
userById: DataLoader<string, User | null>;
};
};
export function createContext(): Context {
return {
loaders: {
userById: new DataLoader(async (ids) => userStore.findManyByIds([...ids])),
},
};
}
export const resolvers = {
Query: {
session: (_: unknown, args: { id: string }, ctx: Context) => {
requireAuth(ctx);
return sessionStore.findByIdForUser(args.id, ctx.userId!);
},
},
Session: {
owner: (session: Session, _: unknown, ctx: Context) => ctx.loaders.userById.load(session.ownerId),
},
};
Production Controls
- Use cursor pagination for lists; require
first/last limits with max bounds.
- Reject anonymous introspection in production unless the API is intentionally public.
- Use persisted operations for first-party clients when possible.
- Limit depth and complexity; GraphQL can express expensive recursive queries.
- Avoid resolver-level N+1 queries with per-request DataLoader instances.
- Do not put authorization solely in schema directives unless backed by tested resolver/service checks.
Verification
pnpm test
pnpm exec graphql-inspector validate schema.graphql
Test at least: unauthorized field access, nested list limits, DataLoader batching, and error masking.
Resources
Principles
- Schema is the public contract.
- Every resolver runs under authorization.
- Execution cost must be bounded.
- DataLoader is request-scoped.
- Nullability is an error-handling decision.
Source: ig-vikas/SkillRegistry — distributed by TomeVault.
1---2name: graphql-expert-23description: GraphQL schema, resolver, authorization, DataLoader, pagination, query cost/depth limiting, error masking, and production server guidance. Use when this capability is needed.4---56# GraphQL Expert78Design GraphQL APIs around explicit schema contracts, bounded execution cost, resolver batching, field-level authorization, and predictable pagination.910## Workflow11121. Model the schema from client use cases and domain boundaries.132. Define nullability intentionally; nullable fields are how partial failures surface.143. Add authorization in resolvers or service methods, not only at the endpoint.154. Use DataLoader per request to batch and cache nested resolver loads.165. Add operation depth, token, cost, and rate limits before exposing public GraphQL.176. Mask internal errors and log with request IDs.1819## Resolver Pattern2021```typescript22import DataLoader from "dataloader";2324type Context = {25 userId?: string;26 loaders: {27 userById: DataLoader<string, User | null>;28 };29};3031export function createContext(): Context {32 return {33 loaders: {34 userById: new DataLoader(async (ids) => userStore.findManyByIds([...ids])),35 },36 };37}3839export const resolvers = {40 Query: {41 session: (_: unknown, args: { id: string }, ctx: Context) => {42 requireAuth(ctx);43 return sessionStore.findByIdForUser(args.id, ctx.userId!);44 },45 },46 Session: {47 owner: (session: Session, _: unknown, ctx: Context) => ctx.loaders.userById.load(session.ownerId),48 },49};50```5152## Production Controls5354- Use cursor pagination for lists; require `first`/`last` limits with max bounds.55- Reject anonymous introspection in production unless the API is intentionally public.56- Use persisted operations for first-party clients when possible.57- Limit depth and complexity; GraphQL can express expensive recursive queries.58- Avoid resolver-level N+1 queries with per-request DataLoader instances.59- Do not put authorization solely in schema directives unless backed by tested resolver/service checks.6061## Verification6263```bash64pnpm test65pnpm exec graphql-inspector validate schema.graphql66```6768Test at least: unauthorized field access, nested list limits, DataLoader batching, and error masking.6970## Resources7172- **[GraphQL Learn](https://graphql.org/learn/)** - Official GraphQL concepts.73- **[GraphQL Pagination](https://graphql.org/learn/pagination/)** - Cursor connection guidance.74- **[Envelop](https://the-guild.dev/graphql/envelop/docs)** - Plugin layer for validation, logging, masking, and limits.75- **[GraphQL Yoga Production](https://the-guild.dev/graphql/yoga-server/docs/prepare-for-production)** - Production security and monitoring guidance.76- **[DataLoader](https://github.com/graphql/dataloader)** - Batching/caching utility.7778## Principles79801. Schema is the public contract.812. Every resolver runs under authorization.823. Execution cost must be bounded.834. DataLoader is request-scoped.845. Nullability is an error-handling decision.8586---87> Source: [ig-vikas/SkillRegistry](https://github.com/ig-vikas/SkillRegistry) — distributed by [TomeVault](https://tomevault.io).88<!-- tomevault:4.0:skill_md:2026-06-15 -->