Skip to content

Commit e3ed3ad

Browse files
authored
refactor: GraphQL operations (#756)
* docs: skill graphql-operations * refactor: graphql operations * docs: update AGENTS.md with learnings * chore: changeset * chore: devcontainer save claude sessions to local machine * feat: devcontainer claude persist * docs: delete custom agent
1 parent 4549d45 commit e3ed3ad

22 files changed

Lines changed: 2609 additions & 195 deletions

File tree

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
---
2+
name: graphql-operations
3+
description: >
4+
Guide for writing GraphQL operations (queries, mutations, fragments) following best practices. Use this skill when:
5+
(1) writing GraphQL queries or mutations,
6+
(2) organizing operations with fragments,
7+
(3) optimizing data fetching patterns,
8+
(4) setting up type generation or linting,
9+
(5) reviewing operations for efficiency.
10+
license: MIT
11+
compatibility: Any GraphQL client (Apollo Client, urql, Relay, etc.)
12+
metadata:
13+
author: apollographql
14+
version: "1.0.0"
15+
allowed-tools: Bash(npm:*) Bash(npx:*) Read Write Edit Glob Grep
16+
---
17+
18+
# GraphQL Operations Guide
19+
20+
This guide covers best practices for writing GraphQL operations (queries, mutations, subscriptions) as a client developer. Well-written operations are efficient, type-safe, and maintainable.
21+
22+
## Operation Basics
23+
24+
### Query Structure
25+
26+
```graphql
27+
query GetUser($id: ID!) {
28+
user(id: $id) {
29+
id
30+
name
31+
email
32+
}
33+
}
34+
```
35+
36+
### Mutation Structure
37+
38+
```graphql
39+
mutation CreatePost($input: CreatePostInput!) {
40+
createPost(input: $input) {
41+
id
42+
title
43+
createdAt
44+
}
45+
}
46+
```
47+
48+
### Subscription Structure
49+
50+
```graphql
51+
subscription OnMessageReceived($channelId: ID!) {
52+
messageReceived(channelId: $channelId) {
53+
id
54+
content
55+
sender {
56+
id
57+
name
58+
}
59+
}
60+
}
61+
```
62+
63+
## Quick Reference
64+
65+
### Operation Naming
66+
67+
| Pattern | Example |
68+
| ------------ | ------------------------------------------- |
69+
| Query | `GetUser`, `ListPosts`, `SearchProducts` |
70+
| Mutation | `CreateUser`, `UpdatePost`, `DeleteComment` |
71+
| Subscription | `OnMessageReceived`, `OnUserStatusChanged` |
72+
73+
### Variable Syntax
74+
75+
```graphql
76+
# Required variable
77+
query GetUser($id: ID!) { ... }
78+
79+
# Optional variable with default
80+
query ListPosts($first: Int = 20) { ... }
81+
82+
# Multiple variables
83+
query SearchPosts($query: String!, $status: PostStatus, $first: Int = 10) { ... }
84+
```
85+
86+
### Fragment Syntax
87+
88+
```graphql
89+
# Define fragment
90+
fragment UserBasicInfo on User {
91+
id
92+
name
93+
avatarUrl
94+
}
95+
96+
# Use fragment
97+
query GetUser($id: ID!) {
98+
user(id: $id) {
99+
...UserBasicInfo
100+
email
101+
}
102+
}
103+
```
104+
105+
### Directives
106+
107+
```graphql
108+
query GetUser($id: ID!, $includeEmail: Boolean!) {
109+
user(id: $id) {
110+
id
111+
name
112+
email @include(if: $includeEmail)
113+
}
114+
}
115+
116+
query GetPosts($skipDrafts: Boolean!) {
117+
posts {
118+
id
119+
title
120+
draft @skip(if: $skipDrafts)
121+
}
122+
}
123+
```
124+
125+
## Key Principles
126+
127+
### 1. Request Only What You Need
128+
129+
```graphql
130+
# Good: Specific fields
131+
query GetUserName($id: ID!) {
132+
user(id: $id) {
133+
id
134+
name
135+
}
136+
}
137+
138+
# Avoid: Over-fetching
139+
query GetUser($id: ID!) {
140+
user(id: $id) {
141+
id
142+
name
143+
email
144+
bio
145+
posts {
146+
id
147+
title
148+
content
149+
comments {
150+
id
151+
}
152+
}
153+
followers {
154+
id
155+
name
156+
}
157+
# ... many unused fields
158+
}
159+
}
160+
```
161+
162+
### 2. Name All Operations
163+
164+
```graphql
165+
# Good: Named operation
166+
query GetUserPosts($userId: ID!) {
167+
user(id: $userId) {
168+
posts {
169+
id
170+
title
171+
}
172+
}
173+
}
174+
175+
# Avoid: Anonymous operation
176+
query {
177+
user(id: "123") {
178+
posts {
179+
id
180+
title
181+
}
182+
}
183+
}
184+
```
185+
186+
### 3. Use Variables, Not Inline Values
187+
188+
```graphql
189+
# Good: Variables
190+
query GetUser($id: ID!) {
191+
user(id: $id) {
192+
id
193+
name
194+
}
195+
}
196+
197+
# Avoid: Hardcoded values
198+
query {
199+
user(id: "123") {
200+
id
201+
name
202+
}
203+
}
204+
```
205+
206+
### 4. Colocate Fragments with Components
207+
208+
```tsx
209+
// UserAvatar.tsx
210+
export const USER_AVATAR_FRAGMENT = gql`
211+
fragment UserAvatar on User {
212+
id
213+
name
214+
avatarUrl
215+
}
216+
`;
217+
218+
function UserAvatar({ user }) {
219+
return <img src={user.avatarUrl} alt={user.name} />;
220+
}
221+
```
222+
223+
## Reference Files
224+
225+
Detailed documentation for specific topics:
226+
227+
- [Queries](references/queries.md) - Query patterns and optimization
228+
- [Mutations](references/mutations.md) - Mutation patterns and error handling
229+
- [Fragments](references/fragments.md) - Fragment organization and reuse
230+
- [Variables](references/variables.md) - Variable usage and types
231+
- [Tooling](references/tooling.md) - Code generation and linting
232+
233+
## Ground Rules
234+
235+
- ALWAYS name your operations (no anonymous queries/mutations)
236+
- ALWAYS use variables for dynamic values
237+
- ALWAYS request only the fields you need
238+
- ALWAYS include `id` field for cacheable types
239+
- NEVER hardcode values in operations
240+
- NEVER duplicate field selections across files
241+
- PREFER fragments for reusable field selections
242+
- PREFER colocating fragments with components
243+
- USE descriptive operation names that reflect purpose
244+
- USE `@include`/`@skip` for conditional fields

0 commit comments

Comments
 (0)