Claude-skill-registry graphql-mutations
GraphQL mutation design including payload patterns, field-specific errors, input objects, and HTTP semantics. Use when designing or implementing GraphQL mutations.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/graphql-mutations" ~/.claude/skills/majiayu000-claude-skill-registry-graphql-mutations && rm -rf "$T"
manifest:
skills/data/graphql-mutations/SKILL.mdsource content
GraphQL Mutations
Expert guidance for designing effective GraphQL mutations.
Quick Reference
| Pattern | Use When | Structure |
|---|---|---|
| Result payload | All mutations | |
| Field-specific errors | Validation failures | in payload |
| Input objects | Complex arguments | |
| Noun + Verb naming | State changes | , , |
| Idempotent mutations | Safe retries | Design for repeatable calls |
| Optimistic UI | Client-side updates | Return predicted result |
What Do You Need?
- Payload design - Return types, error handling
- Input objects - Structuring mutation arguments
- Error patterns - Field-specific vs top-level errors
- Naming - Mutation naming conventions
- Side effects - Handling async operations
Specify a number or describe your mutation scenario.
Routing
| Response | Reference to Read |
|---|---|
| 1, "payload", "return", "response" | payloads.md |
| 2, "input", "argument", "parameter" | inputs.md |
| 3, "error", "validation", "field error" | errors.md |
| 4, "naming", "convention" | naming.md |
| 5, general mutations | Read relevant references |
Critical Rules
- Always return a payload: Never just a boolean or the object
- Use input objects for complex arguments: Don't use many scalars
- Field-specific errors in response: Let clients handle per-field failures
- Noun + verb naming: createUser, deleteUser, not user
- Mutations are POST-only: Never use GET for mutations
- Design for idempotency: Safe to call multiple times
Mutation Template
# Input object for complex arguments input CreateUserInput { name: String! email: String! password: String! } # Payload with result and errors type CreateUserPayload { user: User errors: [UserError!]! } # Field-specific error type type UserError { field: [String!]! # Path to field: ["email"] or ["user", "emails", 0] message: String! } # Mutation definition type Mutation { """ Creates a new user account """ createUser(input: CreateUserInput!): CreateUserPayload! }
Mutation Implementation
// Good: Mutation with proper payload and field errors func (r *mutationResolver) CreateUser(ctx context.Context, input CreateUserInput) (*CreateUserPayload, error) { // Validate var errs []UserError if input.Name == "" { errs = append(errs, UserError{ Field: []string{"name"}, Message: "Name is required", }) } if !isValidEmail(input.Email) { errs = append(errs, UserError{ Field: []string{"email"}, Message: "Invalid email format", }) } if len(errs) > 0 { return &CreateUserPayload{Errors: errs}, nil } // Create user, err := r.db.CreateUser(input) if err != nil { if errors.Is(err, db.ErrDuplicate) { return &CreateUserPayload{ Errors: []UserError{{ Field: []string{"email"}, Message: "Email already exists", }}, }, nil } return nil, fmt.Errorf("failed to create user") } return &CreateUserPayload{User: user, Errors: []UserError{}}, nil }
Common Mutation Patterns
Create
type Mutation { createUser(input: CreateUserInput!): CreateUserPayload! } type CreateUserPayload { user: User errors: [UserError!]! }
Update
type Mutation { updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload! } type UpdateUserPayload { user: User errors: [UserError!]! }
Delete
type Mutation { deleteUser(id: ID!): DeleteUserPayload! } type DeleteUserPayload { deletedUserId: ID errors: [UserError!]! }
State Change (Noun + Verb)
type Mutation { """ Closes a card (marks as closed, not deleted) """ closeCard(id: ID!): CloseCardPayload! } type CloseCardPayload { card: Card errors: [UserError!]! }
Error Handling Patterns
| Error Type | Response Pattern |
|---|---|
| Validation errors | Return in payload errors field |
| Duplicate unique key | Return in payload errors field |
| Not found | Return in payload errors field |
| Permission denied | Return in payload errors field |
| Internal server error | Return nil, wrap error (don't expose) |
HTTP Semantics
| Concern | Guidance |
|---|---|
| HTTP method | Always POST for mutations |
| Caching | Mutations are never cached |
| Idempotency | Design mutations to be safely repeatable |
| Side effects | Document non-obvious side effects |
| Async operations | Return payload with job ID, query for status |
Common Mutation Mistakes
| Mistake | Severity | Fix |
|---|---|---|
| Returning just boolean | Medium | Use payload with result |
| No field-specific errors | High | Add errors array to payload |
| Too many scalar arguments | Medium | Use input object |
| Verb + noun naming | Low | Use noun + verb (createUser) |
| Using GET for mutations | Critical | Always use POST |
| No validation errors in payload | High | Return validation failures |
Reference Index
| File | Topics |
|---|---|
| payloads.md | Result types, error patterns, response structure |
| inputs.md | Input objects, nested inputs, validation |
| errors.md | Field errors, error types, client handling |
| naming.md | Conventions, verb selection, consistency |
Success Criteria
Mutations are well-designed when:
- All mutations return a payload type
- Field-specific errors returned in payload
- Input objects used for complex arguments
- Noun + verb naming (createUser, deletePost)
- POST only (never GET)
- Idempotent where possible
- Validation errors returned, not thrown
- No internal errors exposed to clients