Back to Skills

use-graphql-api

pjt222
Updated 2 days ago
4 views
17
2
17
View on GitHub
Metaaiapiautomationdesigndata

About

This skill enables CLI-based GraphQL API interactions, including schema introspection, query/mutation construction, and response parsing with tools like `gh api graphql` and `jq`. It's designed for automating GitHub operations or integrating with any GraphQL endpoint from scripts. Developers can chain operations by piping data between calls for building structured CLI workflows.

Quick Install

Claude Code

Recommended
Primary
npx skills add pjt222/agent-almanac -a claude-code
Plugin CommandAlternative
/plugin add https://github.com/pjt222/agent-almanac
Git CloneAlternative
git clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/use-graphql-api

Copy and paste this command in Claude Code to install this skill

Documentation

Use GraphQL API

Discover, construct, exec, chain GraphQL ops from CLI.

Use When

  • Query|mutate via GraphQL endpoint (GitHub, Hasura, Apollo, etc.)
  • Auto GitHub ops requiring GraphQL (Discussions, Projects v2)
  • Shell scripts fetching structured data from GraphQL
  • Chain multi calls → out → next

In

  • Required: GraphQL endpoint URL|service ("github")
  • Required: Op intent (data to read|write)
  • Optional: Auth token|method (default: gh CLI for GitHub)
  • Optional: Out format (raw JSON, jq-filtered, var assignment)

Do

Step 1. Discover Schema

Determine types, fields, queries, mutations.

GitHub:

# List available query fields
gh api graphql -f query='{ __schema { queryType { fields { name description } } } }' \
  | jq '.data.__schema.queryType.fields[] | {name, description}'

# List available mutation fields
gh api graphql -f query='{ __schema { mutationType { fields { name description } } } }' \
  | jq '.data.__schema.mutationType.fields[] | {name, description}'

# Inspect a specific type
gh api graphql -f query='{
  __type(name: "Repository") {
    fields { name type { name kind ofType { name } } }
  }
}' | jq '.data.__type.fields[] | {name, type: .type.name // .type.ofType.name}'

Generic endpoints:

# Full introspection query via curl
curl -s -X POST https://api.example.com/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"query":"{ __schema { types { name kind fields { name } } } }"}' \
  | jq '.data.__schema.types[] | select(.kind == "OBJECT") | {name, fields: [.fields[].name]}'

Got: JSON listing types, fields, mutations. Schema confirms endpoint reachable + auth valid.

If err:

  • 401 Unauthorized → verify token; GitHub: gh auth status
  • Cannot query field → endpoint may disable introspection → consult docs
  • Conn refused → verify URL + net

Step 2. ID Op Type

Query (read), mutation (write), subscription (stream).

IntentOperationExample
Fetch dataqueryGet repository details, list discussions
Create/update/deletemutationCreate a discussion, add a comment
Real-time updatessubscriptionWatch for new issues (rare in CLI)

GitHub-specific → GitHub GraphQL API docs.

# Quick check: does the mutation exist?
gh api graphql -f query='{ __schema { mutationType { fields { name } } } }' \
  | jq '.data.__schema.mutationType.fields[].name' | grep -i "discussion"

Got: Clear ID query|mutation needed + exact op name (createDiscussion, repository).

If err:

  • Op not found → broader terms or check API ver
  • Unclear → action changes state = mutation

Step 3. Construct Op

Build query|mutation w/ fields, args, vars.

Query example — fetch repo's discussion categories:

gh api graphql -f query='
  query($owner: String!, $repo: String!) {
    repository(owner: $owner, name: $repo) {
      discussionCategories(first: 10) {
        nodes { id name }
      }
    }
  }
' -f owner="OWNER" -f repo="REPO" | jq '.data.repository.discussionCategories.nodes'

Mutation example — create GitHub Discussion:

gh api graphql -f query='
  mutation($repoId: ID!, $categoryId: ID!, $title: String!, $body: String!) {
    createDiscussion(input: {
      repositoryId: $repoId,
      categoryId: $categoryId,
      title: $title,
      body: $body
    }) {
      discussion { url number }
    }
  }
' -f repoId="$REPO_ID" -f categoryId="$CAT_ID" \
  -f title="My Discussion" -f body="Discussion body here"

Construction rules:

  1. Always vars ($var: Type!) not inline → reusability
  2. Request only fields needed → minimize res size
  3. first: N w/ nodes for paginated connections
  4. Add id to every obj selection → need for chaining

Got: Syntactically valid op w/ vars, field selections, pagination.

If err:

  • Syntax errs → bracket matching + trailing commas (GraphQL no trailing commas)
  • Type mismatch → verify var types vs schema (ID! vs String!)
  • Missing required fields → add per schema

Step 4. Exec via CLI

Run + capture res.

GitHub — gh api graphql:

# Simple query
gh api graphql -f query='{ viewer { login } }'

# With variables
gh api graphql \
  -f query='query($owner: String!, $repo: String!) {
    repository(owner: $owner, name: $repo) { id name }
  }' \
  -f owner="octocat" -f repo="Hello-World"

# With jq post-processing
REPO_ID=$(gh api graphql \
  -f query='query($owner: String!, $repo: String!) {
    repository(owner: $owner, name: $repo) { id }
  }' \
  -f owner="OWNER" -f repo="REPO" \
  --jq '.data.repository.id')

Generic endpoint — curl:

curl -s -X POST "$GRAPHQL_ENDPOINT" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d "$(jq -n \
    --arg query 'query { users { id name } }' \
    '{query: $query}'
  )"

Got: JSON res w/ data key containing requested fields, or errors array if op failed.

If err:

  • errors in res → read msg; common: missing perms, invalid IDs, rate limits
  • Empty data → query matched no records → verify input
  • HTTP 403 → token lacks scope; GitHub: gh auth status + gh auth refresh -s scope

Step 5. Parse Res

Extract data from JSON.

# Extract a single value
gh api graphql -f query='{ viewer { login } }' --jq '.data.viewer.login'

# Extract from a list
gh api graphql -f query='
  query($owner: String!, $repo: String!) {
    repository(owner: $owner, name: $repo) {
      issues(first: 5, states: OPEN) {
        nodes { number title }
      }
    }
  }
' -f owner="OWNER" -f repo="REPO" \
  --jq '.data.repository.issues.nodes[] | "\(.number): \(.title)"'

# Assign to a variable for later use
CATEGORY_ID=$(gh api graphql -f query='
  query($owner: String!, $repo: String!) {
    repository(owner: $owner, name: $repo) {
      discussionCategories(first: 20) {
        nodes { id name }
      }
    }
  }
' -f owner="OWNER" -f repo="REPO" \
  --jq '.data.repository.discussionCategories.nodes[] | select(.name == "Show and Tell") | .id')

Got: Clean extracted vals → display|shell var.

If err:

  • jq returns null → field path wrong → pipe raw JSON to jq . to inspect structure
  • Multi vals when expecting one → select() filter or | first
  • Unicode → -r to jq for raw string out

Step 6. Chain Ops

Out from one → input to next.

# Step A: Get the repository ID
REPO_ID=$(gh api graphql \
  -f query='query($owner: String!, $repo: String!) {
    repository(owner: $owner, name: $repo) { id }
  }' \
  -f owner="$OWNER" -f repo="$REPO" \
  --jq '.data.repository.id')

# Step B: Get the discussion category ID
CAT_ID=$(gh api graphql \
  -f query='query($owner: String!, $repo: String!) {
    repository(owner: $owner, name: $repo) {
      discussionCategories(first: 20) {
        nodes { id name }
      }
    }
  }' \
  -f owner="$OWNER" -f repo="$REPO" \
  --jq '.data.repository.discussionCategories.nodes[]
    | select(.name == "Show and Tell") | .id')

# Step C: Create the discussion using both IDs
RESULT=$(gh api graphql \
  -f query='mutation($repoId: ID!, $catId: ID!, $title: String!, $body: String!) {
    createDiscussion(input: {
      repositoryId: $repoId,
      categoryId: $catId,
      title: $title,
      body: $body
    }) {
      discussion { url number }
    }
  }' \
  -f repoId="$REPO_ID" -f catId="$CAT_ID" \
  -f title="$TITLE" -f body="$BODY" \
  --jq '.data.createDiscussion.discussion')

echo "Created: $(echo "$RESULT" | jq -r '.url')"

Pattern: Always extract id in earlier queries → pass as ID! vars to subsequent mutations.

Got: Multi-step workflow → each call succeeds + IDs flow correctly.

If err:

  • Var empty → prev step failed silent → set -e + check each intermediate
  • ID format wrong → GitHub node IDs opaque strings (R_kgDO...) → never construct manually
  • Rate limited → sleep 1 between calls or batch w/ aliases

Check

  1. Introspection returns schema (Step 1)
  2. Constructed queries syntactically valid (no parser errs)
  3. Res contains data w/o errors
  4. Extracted vals match expected types (IDs non-empty strings, counts numbers)
  5. Chained ops complete end-to-end (mutation uses IDs from prior queries)

Traps

PitfallPrevention
Forgetting ! on required variable typesAlways check schema for nullability; most input fields are non-null (!)
Using REST IDs in GraphQLGraphQL uses opaque node IDs; fetch them via GraphQL, not REST
Not paginating large result setsUse first/after with pageInfo { hasNextPage endCursor }
Hardcoding IDs instead of querying themIDs differ between environments; always query dynamically
Ignoring the errors arrayCheck for errors even when data is present — partial errors are possible
Shell quoting issues with nested JSONUse --jq flag with gh or pipe through jq separately

GitHub Repository

pjt222/agent-almanac
Path: i18n/caveman-ultra/skills/use-graphql-api
0
agentsagentskillsai-assisted-developmentclaude-codeskillsteams

Related Skills

content-collections

Meta

This skill provides a production-tested setup for Content Collections, a TypeScript-first tool that transforms Markdown/MDX files into type-safe data collections with Zod validation. Use it when building blogs, documentation sites, or content-heavy Vite + React applications to ensure type safety and automatic content validation. It covers everything from Vite plugin configuration and MDX compilation to deployment optimization and schema validation.

View skill

polymarket

Meta

This skill enables developers to build applications with the Polymarket prediction markets platform, including API integration for trading and market data. It also provides real-time data streaming via WebSocket to monitor live trades and market activity. Use it for implementing trading strategies or creating tools that process live market updates.

View skill

creating-opencode-plugins

Meta

This skill helps developers create OpenCode plugins that hook into 25+ event types like commands, files, and LSP operations. It provides the plugin structure, event API specifications, and implementation patterns for JavaScript/TypeScript modules. Use it when you need to intercept, monitor, or extend the OpenCode AI assistant's lifecycle with custom event-driven logic.

View skill

sglang

Meta

SGLang is a high-performance LLM serving framework that specializes in fast, structured generation for JSON, regex, and agentic workflows using its RadixAttention prefix caching. It delivers significantly faster inference, especially for tasks with repeated prefixes, making it ideal for complex, structured outputs and multi-turn conversations. Choose SGLang over alternatives like vLLM when you need constrained decoding or are building applications with extensive prefix sharing.

View skill