writing-graphql-operations

GraphQL Operations Developer

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "writing-graphql-operations" with this command: npx skills add saleor/configurator/saleor-configurator-writing-graphql-operations

GraphQL Operations Developer

Overview

Guide the creation and maintenance of GraphQL operations following project conventions for type safety, organization, error handling, and testing with gql.tada and urql.

When to Use

  • Creating new GraphQL queries or mutations

  • Integrating with Saleor API endpoints

  • Updating schema after Saleor changes

  • Working with urql client configuration

  • Creating MSW mocks for testing

Quick Reference

Tool Purpose

gql.tada Type-safe GraphQL with TypeScript inference

urql GraphQL client with caching

@urql/exchange-auth Authentication (Bearer token)

@urql/exchange-retry Rate limit retry (429, max 5 attempts)

File Organization

src/lib/graphql/ ├── client.ts # urql client configuration ├── operations/ # GraphQL operation definitions ├── fragments/ # Reusable GraphQL fragments ├── mocks/ # MSW test mocks └── schema.graphql # Saleor schema (generated)

src/modules/<entity>/ ├── repository.ts # Uses GraphQL operations └── ...

Creating Operations

Use gql.tada for all operations. Types are inferred from schema automatically:

import { graphql } from 'gql.tada';

export const GetCategoriesQuery = graphql( query GetCategories($first: Int!) { categories(first: $first) { edges { node { id, name, slug, description } } } });

// Type inferred automatically type GetCategoriesResult = ResultOf<typeof GetCategoriesQuery>;

For shared fields, extract fragments and pass as second argument to graphql() .

Repository Pattern

Each entity has a repository class that encapsulates GraphQL operations and maps responses to domain models:

export class CategoryRepository { constructor(private readonly client: Client) {}

async findAll(): Promise<Category[]> { const result = await this.client.query(GetCategoriesQuery, { first: 100 }); if (result.error) { throw GraphQLError.fromCombinedError(result.error, 'GetCategories'); } return this.mapCategories(result.data?.categories); }

async create(input: CategoryInput): Promise<Category> { const result = await this.client.mutation(CreateCategoryMutation, { input }); if (result.error) { throw GraphQLError.fromCombinedError(result.error, 'CreateCategory'); } if (result.data?.categoryCreate?.errors?.length) { throw new GraphQLError('Category creation failed', result.data.categoryCreate.errors); } return this.mapCategory(result.data?.categoryCreate?.category); } }

Key pattern: Always map GraphQL responses to domain models in the repository. Never expose GraphQL types to services.

Error Handling

Two error types to always check:

  • Network/GraphQL errors (result.error ): Wrap with GraphQLError.fromCombinedError(error, 'OperationName', { context })

  • Mutation validation errors (result.data?.mutation?.errors ): Check array length, throw with field details

See references/error-handling.md for complete error patterns, classification, and MSW error mocking.

Schema Management

pnpm fetch-schema # Updates schema.graphql and graphql-env.d.ts

Update schema when: new Saleor features needed, after Saleor version upgrade, or when encountering schema drift errors. Always commit schema changes with the feature implementation.

Testing

Mock GraphQL operations with MSW using graphql.query() and graphql.mutation() handlers. See analyzing-test-coverage skill for full MSW setup patterns.

Client Configuration

The urql client is configured in src/lib/graphql/client.ts with: cacheExchange , authExchange (Bearer token), retryExchange (1s-15s backoff, 5 attempts, retries on 429 and network errors), and fetchExchange .

Best Practices

Do:

  • Use gql.tada for all operations (automatic type inference)

  • Keep operations close to their domain modules

  • Map GraphQL responses to domain models in repository

  • Include operation name in error context

  • Update mocks when schema changes

  • Extract shared fields to fragments

Don't:

  • Use raw string queries (no type safety)

  • Expose GraphQL types directly to services

  • Skip error handling for any operation

  • Hardcode pagination limits (use constants)

Validation Checkpoints

Phase Validate Command

Schema fresh No drift pnpm fetch-schema

Operations typed gql.tada inference Check IDE types

Mocks match MSW handlers pnpm test

Error handling All paths covered Code review

Common Mistakes

Mistake Fix

Not checking errors array Always check result.data?.mutation?.errors

Exposing GraphQL types Map to domain types in repository

Missing error context Include operation name in errors

Stale schema Run pnpm fetch-schema after Saleor updates

Not using fragments Extract shared fields to fragments

External Documentation

For up-to-date library docs, use Context7 MCP:

  • urql: resolve-library-id with /urql-graphql/urql

  • gql.tada: resolve-library-id with "gql.tada"

References

Skill Reference Files

  • Error Handling - Error types, wrapping, classification, and MSW error mocking

  • Fragment Patterns - Fragment composition and type inference

Project Resources

  • src/lib/graphql/client.ts

  • Client configuration

  • src/lib/graphql/operations/

  • Existing operations

  • docs/CODE_QUALITY.md#graphql--external-integrations

  • Quality standards

Related Skills

  • Complete entity workflow: See adding-entity-types for full implementation including bulk mutations

  • Bulk operations: See adding-entity-types/references/bulk-mutations.md for chunking patterns

  • Testing GraphQL: See analyzing-test-coverage for MSW setup

Troubleshooting

Common Error Scenarios

Error Cause Fix

CombinedError: [Network]

API unreachable or URL malformed Verify --url ends with /graphql/ and instance is running

CombinedError: [GraphQL]

Invalid query or variables Run pnpm fetch-schema and check operation against schema

result.data?.mutation?.errors non-empty Saleor validation rejection Read field and message from errors array for specifics

TypeError: Cannot read property of undefined

Missing null check on response Always check result.data before accessing nested properties

HTTP 429 (rate limited) Too many requests Built-in retry exchange handles this; increase delay if persistent

Debugging Steps

  • Check schema freshness: pnpm fetch-schema — ensures local schema matches remote

  • Isolate the operation: Test the query/mutation in Saleor's GraphQL Playground first

  • Add error context: Include operation name in all error wrapping calls

  • Check MSW handlers: Ensure test mocks match updated operation signatures

  • Verify type inference: Hover over ResultOf<typeof Query> in IDE to confirm types

Quick Reference Rule

For a condensed quick reference, see .claude/rules/graphql-patterns.md (automatically loaded when editing GraphQL operations and repository files).

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

reviewing-typescript-code

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

managing-github-ci

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

implementing-cli-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

configurator-cli

No summary provided by upstream source.

Repository SourceNeeds Review