GraphQL APIs AI Skill Guide
Overview & Engine Architecture
GraphQL exposes a typed schema (types, queries, mutations, subscriptions) where clients ask for exact fields. Servers resolve fields via resolvers; naive per-field DB access causes N+1 queries. Agents design schemas for product use cases, enforce authz at resolver/field level, batch loads (DataLoader), and treat persisted/allowlisted operations as a production hardening option.
Client query
|
GraphQL runtime (parse/validate/execute)
|
resolvers (+ DataLoader)
|
services / DB
When to use this skill
- Designing or evolving GraphQL schemas
- Implementing resolvers without N+1 pathologies
- Adding authn/authz around sensitive fields
- Pairing GraphQL with Express, FastAPI, or Spring hosts
Operational directives
- Schema-first (or code-first with schema as contract) - clients depend on stable types.
- Never trust client-provided IDs without authz checks in resolvers.
- Batch and cache per-request DB lookups (DataLoader or equivalent).
- Prefer pagination (
connection/ cursor) for lists that can grow. - Limit query depth/complexity in public APIs; disable introspection in prod if policy requires.
Schema + resolver sketch
type Item {
id: ID!
sku: String!
qty: Int!
}
type Query {
item(id: ID!): Item
items(first: Int = 20): [Item!]!
}
type Mutation {
createItem(sku: String!, qty: Int!): Item!
}
// Pseudocode resolver map
const resolvers = {
Query: {
item: (_: unknown, { id }: { id: string }, ctx: Ctx) => ctx.items.byId(id),
items: (_: unknown, { first }: { first: number }, ctx: Ctx) =>
ctx.items.list(Math.min(first, 100)),
},
Mutation: {
createItem: async (_: unknown, args: { sku: string; qty: number }, ctx: Ctx) => {
ctx.requireUser();
return ctx.items.create(args);
},
},
};
Commands
# Depends on stack - examples:
npm run codegen # GraphQL Code Generator
npx rover graph check # schema checks when using Apollo tooling
Common pitfalls
| Pitfall | Why it hurts | Fix |
|---|---|---|
| N+1 field resolvers | Latency explosion | DataLoader / joins |
| Auth only at gateway | Field leaks | Per-field/resolver checks |
| Unlimited list fields | DoS / huge payloads | Pagination + limits |
| Breaking field removals | Client outages | Deprecate first |
Best practices
- Version via additive evolution; use
@deprecatedbefore removal. - Colocate input validation with mutation args.
- Emit operation names in logs for supportability.
- Test resolvers with representative query documents, not only unit mocks.
Limitations
- File uploads and subscriptions need transport-specific setup.
- Federated graphs add ownership and composition complexity.
- Caching differs from REST - think about persisted queries and CDN carefully.
Related skills
@express/@fastapi/@spring-boot- HTTP hosts@prisma- typed DB access behind resolvers@playwright- end-to-end against GraphQL-backed UIs