GraphQL Expert
Expert guidance for GraphQL API development, schema design, resolvers, subscriptions, and best practices for building type-safe, efficient APIs.
Core Concepts
Schema Design
- Type system and schema definition language (SDL)
- Object types, interfaces, unions, and enums
- Input types and custom scalars
- Schema stitching and federation
- Modular schema organization
Resolvers
- Resolver functions and data sources
- Context and info arguments
- Field-level resolvers
- Resolver chains and data loaders
- Error handling in resolvers
Queries and Mutations
- Query design and naming conventions
- Mutation patterns and best practices
- Input validation and sanitization
- Pagination strategies (cursor-based, offset)
- Filtering and sorting
Subscriptions
- Real-time updates with WebSocket
- Subscription resolvers
- PubSub patterns
- Subscription filtering
- Connection management
Performance
- N+1 query problem and DataLoader
- Query complexity analysis
- Depth limiting and query cost
- Caching strategies (field-level, full response)
- Batching and deduplication
GraphQL Federation
Federated Schema
// Users service
import { buildSubgraphSchema } from '@apollo/subgraph';
const typeDefs = gql`
extend schema @link(url: "https://specs.apollo.dev/federation/v2.3")
type User @key(fields: "id") {
id: ID!
email: String!
name: String!
}
type Query {
user(id: ID!): User
users: [User!]!
}
`;
const resolvers = {
User: {
__resolveReference: async (reference, { dataSources }) => {
return dataSources.userAPI.getUserById(reference.id);
},
},
Query: {
user: (_, { id }, { dataSources }) => dataSources.userAPI.getUserById(id),
users: (_, __, { dataSources }) => dataSources.userAPI.getUsers(),
},
};
// Posts service
const typeDefs = gql`
extend schema @link(url: "https://specs.apollo.dev/federation/v2.3")
type Post @key(fields: "id") {
id: ID!
title: String!
content: String!
author: User!
}
extend type User @key(fields: "id") {
id: ID! @external
posts: [Post!]!
}
type Query {
post(id: ID!): Post
posts: [Post!]!
}
`;
const resolvers = {
Post: {
author: (post) => ({ __typename: 'User', id: post.authorId }),
},
User: {
posts: (user, _, { dataSources }) =>
dataSources.postAPI.getPostsByAuthorId(user.id),
},
};
// Gateway
import { ApolloGateway, IntrospectAndCompose } from '@apollo/gateway';
const gateway = new ApolloGateway({
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
{ name: 'users', url: 'http://localhost:4001/graphql' },
{ name: 'posts', url: 'http://localhost:4002/graphql' },
],
}),
});
const server = new ApolloServer({ gateway });
Anti-Patterns to Avoid
❌ Exposing internal IDs: Use opaque IDs or UUIDs
❌ Overly nested queries: Limit query depth
❌ No pagination: Always paginate lists
❌ Resolving in mutations: Keep mutations focused
❌ Exposing database schema directly: Design API-first
❌ No DataLoader: Leads to N+1 queries
❌ Generic error messages: Provide actionable errors
❌ No versioning strategy: Plan for schema evolution
Testing
import { ApolloServer } from '@apollo/server';
import { describe, it, expect } from 'vitest';
describe('GraphQL Server', () => {
it('should fetch user by id', async () => {
const server = new ApolloServer({ typeDefs, resolvers });
const response = await server.executeOperation({
query: `
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`,
variables: { id: '1' },
});
expect(response.body.kind).toBe('single');
expect(response.body.singleResult.data?.user).toEqual({
id: '1',
name: 'Alice',
email: 'alice@example.com',
});
});
it('should create post', async () => {
const response = await server.executeOperation({
query: `
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
}
}
`,
variables: {
input: {
title: 'Test Post',
content: 'Content',
},
},
});
expect(response.body.singleResult.data?.createPost).toHaveProperty('id');
});
});
Reference Documentation
Detailed material lives alongside this skill and is read on demand:
- Common Patterns — Relay Cursor Pagination, File Upload
- Best Practices — Schema Design, Performance Optimization, Security
- Modern GraphQL Development — Apollo Server 4, DataLoader for N+1 Prevention, GraphQL Codegen, Error Handling, Authentication & Authorization, Subscriptions with WebSocket, GraphQL Client (Apollo Client), Query Complexity & Depth Limiting
Resources
1---2name: graphql-expert3description: Expert-level GraphQL API development with schema design, resolvers, and subscriptions. Use when the user mentions API, apollo, schema, resolvers, subscriptions, or relay, or when the task involves Schema Design, Queries and Mutations, Apollo Server 4, or DataLoader for N+1 Prevention.4---5
6# GraphQL Expert
7
8Expert guidance for GraphQL API development, schema design, resolvers, subscriptions, and best practices for building type-safe, efficient APIs.
9
10## Core Concepts
11
12### Schema Design
13
14- Type system and schema definition language (SDL)
15- Object types, interfaces, unions, and enums
16- Input types and custom scalars
17- Schema stitching and federation
18- Modular schema organization
19
20### Resolvers
21
22- Resolver functions and data sources
23- Context and info arguments
24- Field-level resolvers
25- Resolver chains and data loaders
26- Error handling in resolvers
27
28### Queries and Mutations
29
30- Query design and naming conventions
31- Mutation patterns and best practices
32- Input validation and sanitization
33- Pagination strategies (cursor-based, offset)
34- Filtering and sorting
35
36### Subscriptions
37
38- Real-time updates with WebSocket
39- Subscription resolvers
40- PubSub patterns
41- Subscription filtering
42- Connection management
43
44### Performance
45
46- N+1 query problem and DataLoader
47- Query complexity analysis
48- Depth limiting and query cost
49- Caching strategies (field-level, full response)
50- Batching and deduplication
51
52## GraphQL Federation
53
54### Federated Schema
55
56```typescript
57// Users service
58import { buildSubgraphSchema } from '@apollo/subgraph';
59
60const typeDefs = gql`
61 extend schema @link(url: "https://specs.apollo.dev/federation/v2.3")
62
63 type User @key(fields: "id") {
64 id: ID!
65 email: String!
66 name: String!
67 }
68
69 type Query {
70 user(id: ID!): User
71 users: [User!]!
72 }
73`;
74
75const resolvers = {
76 User: {
77 __resolveReference: async (reference, { dataSources }) => {
78 return dataSources.userAPI.getUserById(reference.id);
79 },
80 },
81 Query: {
82 user: (_, { id }, { dataSources }) => dataSources.userAPI.getUserById(id),
83 users: (_, __, { dataSources }) => dataSources.userAPI.getUsers(),
84 },
85};
86
87// Posts service
88const typeDefs = gql`
89 extend schema @link(url: "https://specs.apollo.dev/federation/v2.3")
90
91 type Post @key(fields: "id") {
92 id: ID!
93 title: String!
94 content: String!
95 author: User!
96 }
97
98 extend type User @key(fields: "id") {
99 id: ID! @external
100 posts: [Post!]!
101 }
102
103 type Query {
104 post(id: ID!): Post
105 posts: [Post!]!
106 }
107`;
108
109const resolvers = {
110 Post: {
111 author: (post) => ({ __typename: 'User', id: post.authorId }),
112 },
113 User: {
114 posts: (user, _, { dataSources }) =>
115 dataSources.postAPI.getPostsByAuthorId(user.id),
116 },
117};
118
119// Gateway
120import { ApolloGateway, IntrospectAndCompose } from '@apollo/gateway';
121
122const gateway = new ApolloGateway({
123 supergraphSdl: new IntrospectAndCompose({
124 subgraphs: [
125 { name: 'users', url: 'http://localhost:4001/graphql' },
126 { name: 'posts', url: 'http://localhost:4002/graphql' },
127 ],
128 }),
129});
130
131const server = new ApolloServer({ gateway });
132```
133
134## Anti-Patterns to Avoid
135
136❌ **Exposing internal IDs**: Use opaque IDs or UUIDs
137❌ **Overly nested queries**: Limit query depth
138❌ **No pagination**: Always paginate lists
139❌ **Resolving in mutations**: Keep mutations focused
140❌ **Exposing database schema directly**: Design API-first
141❌ **No DataLoader**: Leads to N+1 queries
142❌ **Generic error messages**: Provide actionable errors
143❌ **No versioning strategy**: Plan for schema evolution
144
145## Testing
146
147```typescript
148import { ApolloServer } from '@apollo/server';
149import { describe, it, expect } from 'vitest';
150
151describe('GraphQL Server', () => {
152 it('should fetch user by id', async () => {
153 const server = new ApolloServer({ typeDefs, resolvers });
154
155 const response = await server.executeOperation({
156 query: `
157 query GetUser($id: ID!) {
158 user(id: $id) {
159 id
160 name
161 email
162 }
163 }
164 `,
165 variables: { id: '1' },
166 });
167
168 expect(response.body.kind).toBe('single');
169 expect(response.body.singleResult.data?.user).toEqual({
170 id: '1',
171 name: 'Alice',
172 email: 'alice@example.com',
173 });
174 });
175
176 it('should create post', async () => {
177 const response = await server.executeOperation({
178 query: `
179 mutation CreatePost($input: CreatePostInput!) {
180 createPost(input: $input) {
181 id
182 title
183 }
184 }
185 `,
186 variables: {
187 input: {
188 title: 'Test Post',
189 content: 'Content',
190 },
191 },
192 });
193
194 expect(response.body.singleResult.data?.createPost).toHaveProperty('id');
195 });
196});
197```
198
199## Reference Documentation
200
201Detailed material lives alongside this skill and is read on demand:
202
203- [Common Patterns](references/PATTERNS.md) — Relay Cursor Pagination, File Upload
204- [Best Practices](references/BEST_PRACTICES.md) — Schema Design, Performance Optimization, Security
205- [Modern GraphQL Development](references/MODERN_GRAPHQL_DEVELOPMENT.md) — Apollo Server 4, DataLoader for N+1 Prevention, GraphQL Codegen, Error Handling, Authentication & Authorization, Subscriptions with WebSocket, GraphQL Client (Apollo Client), Query Complexity & Depth Limiting
206
207## Resources
208
209- Apollo Server: https://www.apollographql.com/docs/apollo-server/
210- GraphQL Spec: https://spec.graphql.org/
211- DataLoader: https://github.com/graphql/dataloader
212- GraphQL Code Generator: https://the-guild.dev/graphql/codegen
213- GraphQL Tools: https://the-guild.dev/graphql/tools