AgentSkillsCN

graphql-operations

遵循最佳实践编写 GraphQL 操作(查询、突变、片段)。适用于以下场景时使用此技能:(1) 编写 GraphQL 查询或突变;(2) 使用片段组织操作;(3) 优化数据获取模式;(4) 设置类型生成或代码检查;(5) 评估操作的效率。

SKILL.md
--- frontmatter
name: graphql-operations
description: >
  Guide for writing GraphQL operations (queries, mutations, fragments) following best practices. Use this skill when:
  (1) writing GraphQL queries or mutations,
  (2) organizing operations with fragments,
  (3) optimizing data fetching patterns,
  (4) setting up type generation or linting,
  (5) reviewing operations for efficiency.
license: MIT
compatibility: Any GraphQL client (Apollo Client, urql, Relay, etc.)
metadata:
  author: apollographql
  version: "1.0"
allowed-tools: Bash(npm:*) Bash(npx:*) Read Write Edit Glob Grep

GraphQL Operations Guide

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.

Operation Basics

Query Structure

graphql
query GetUser($id: ID!) {
  user(id: $id) {
    id
    name
    email
  }
}

Mutation Structure

graphql
mutation CreatePost($input: CreatePostInput!) {
  createPost(input: $input) {
    id
    title
    createdAt
  }
}

Subscription Structure

graphql
subscription OnMessageReceived($channelId: ID!) {
  messageReceived(channelId: $channelId) {
    id
    content
    sender {
      id
      name
    }
  }
}

Quick Reference

Operation Naming

PatternExample
QueryGetUser, ListPosts, SearchProducts
MutationCreateUser, UpdatePost, DeleteComment
SubscriptionOnMessageReceived, OnUserStatusChanged

Variable Syntax

graphql
# Required variable
query GetUser($id: ID!) { ... }

# Optional variable with default
query ListPosts($first: Int = 20) { ... }

# Multiple variables
query SearchPosts($query: String!, $status: PostStatus, $first: Int = 10) { ... }

Fragment Syntax

graphql
# Define fragment
fragment UserBasicInfo on User {
  id
  name
  avatarUrl
}

# Use fragment
query GetUser($id: ID!) {
  user(id: $id) {
    ...UserBasicInfo
    email
  }
}

Directives

graphql
query GetUser($id: ID!, $includeEmail: Boolean!) {
  user(id: $id) {
    id
    name
    email @include(if: $includeEmail)
  }
}

query GetPosts($skipDrafts: Boolean!) {
  posts {
    id
    title
    draft @skip(if: $skipDrafts)
  }
}

Key Principles

1. Request Only What You Need

graphql
# Good: Specific fields
query GetUserName($id: ID!) {
  user(id: $id) {
    id
    name
  }
}

# Avoid: Over-fetching
query GetUser($id: ID!) {
  user(id: $id) {
    id
    name
    email
    bio
    posts { id title content comments { id } }
    followers { id name }
    # ... many unused fields
  }
}

2. Name All Operations

graphql
# Good: Named operation
query GetUserPosts($userId: ID!) {
  user(id: $userId) {
    posts { id title }
  }
}

# Avoid: Anonymous operation
query {
  user(id: "123") {
    posts { id title }
  }
}

3. Use Variables, Not Inline Values

graphql
# Good: Variables
query GetUser($id: ID!) {
  user(id: $id) {
    id
    name
  }
}

# Avoid: Hardcoded values
query {
  user(id: "123") {
    id
    name
  }
}

4. Colocate Fragments with Components

tsx
// UserAvatar.tsx
export const USER_AVATAR_FRAGMENT = gql`
  fragment UserAvatar on User {
    id
    name
    avatarUrl
  }
`;

function UserAvatar({ user }) {
  return <img src={user.avatarUrl} alt={user.name} />;
}

Reference Files

Detailed documentation for specific topics:

  • Queries - Query patterns and optimization
  • Mutations - Mutation patterns and error handling
  • Fragments - Fragment organization and reuse
  • Variables - Variable usage and types
  • Tooling - Code generation and linting

Ground Rules

  • ALWAYS name your operations (no anonymous queries/mutations)
  • ALWAYS use variables for dynamic values
  • ALWAYS request only the fields you need
  • ALWAYS include id field for cacheable types
  • NEVER hardcode values in operations
  • NEVER duplicate field selections across files
  • PREFER fragments for reusable field selections
  • PREFER colocating fragments with components
  • USE descriptive operation names that reflect purpose
  • USE @include/@skip for conditional fields