Write GraphQL queries, mutations, and subscriptions — fragments, code generation, TypedDocumentNode, variables, error handling, and client setup. Use when writing GraphQL code for Saleor.
Scanned 5/29/2026
Install to Claude Code
npx -y skills add OrcaQubits/agentic-commerce-skills-plugins --skill graphql-dev --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Graphql Dev?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/orcaqubits-graphql-dev)More formats (shields.io, HTML) on the badges page.
---
name: graphql-dev
description: >
Write GraphQL queries, mutations, and subscriptions — fragments, code
generation, TypedDocumentNode, variables, error handling, and client setup.
Use when writing GraphQL code for Saleor.
---
# GraphQL Development for Saleor
## Before writing code
**Fetch live docs**:
1. Web-search `site:docs.saleor.io api-reference` for the current Saleor GraphQL schema and API reference
2. Web-search `site:the-guild.dev graphql-codegen` for GraphQL Code Generator configuration and plugins
3. Web-search `site:graphql.org learn` for GraphQL specification fundamentals
4. Web-search `saleor GraphQL TypedDocumentNode urql` for typed client patterns
5. Fetch `https://docs.saleor.io/docs/developer/api-conventions` for Saleor-specific GraphQL conventions
## GraphQL Fundamentals
| Operation | Purpose | Saleor Example |
|-----------|---------|----------------|
| **Query** | Read data | Fetch products, orders, categories |
| **Mutation** | Write data | Create checkout, update product, complete order |
| **Subscription** | Real-time events | Webhook subscription payloads |
### Saleor API Characteristics
- GraphQL is the **only** API — there are no REST endpoints
- All operations are accessed at a single `/graphql/` endpoint
- Mutations return both the result object and an `errors` array
- Queries support filtering, sorting, and cursor-based pagination
- Channel context is set via the `channel` argument or HTTP header
## Fragments for Reuse
| Fragment Use Case | Benefit |
|-------------------|---------|
| **Product fields** | Reuse across product list, detail, and search queries |
| **Address fields** | Share between checkout, order, and customer queries |
| **Money fields** | Consistent currency/amount selection |
| **Error fields** | Uniform error handling across mutations |
| **Image fields** | Consistent image URL and alt text selection |
- Name fragments as `{TypeName}Fragment` (e.g., `ProductFragment`, `AddressFragment`)
- Keep fragments focused on a single concern
- Co-locate fragments with the components that use them
## Variables and Input Types
| Concept | Description | Example |
|---------|-------------|---------|
| **Variable** | Dynamic value passed to operation | `$id: ID!`, `$channel: String!` |
| **Input type** | Structured input for mutations | `ProductCreateInput`, `CheckoutCreateInput` |
| **Required** | Non-null variable | `$id: ID!` (with `!`) |
| **Optional** | Nullable variable | `$filter: ProductFilterInput` |
| **Default** | Variable with default value | `$first: Int = 10` |
- Always use variables instead of string interpolation for dynamic values
- Pass channel as a variable for multi-channel operations
## GraphQL Code Generation
| Package | Purpose |
|---------|---------|
| `@graphql-codegen/cli` | Code generation CLI |
| `@graphql-codegen/typescript` | Generate TypeScript types from schema |
| `@graphql-codegen/typescript-operations` | Generate types for operations |
| `@graphql-codegen/typed-document-node` | Generate TypedDocumentNode objects |
### Configuration (codegen.ts)
| Setting | Value | Description |
|---------|-------|-------------|
| `schema` | Saleor GraphQL endpoint URL | Source of truth for types |
| `documents` | `"src/**/*.graphql"` or `"src/**/*.ts"` | Location of operations |
| `generates` | Output file paths | Where to write generated code |
| `plugins` | Array of codegen plugins | Which code to generate |
- Run `graphql-codegen` after schema changes or when adding new operations
- Commit generated files to version control for CI consistency
## TypedDocumentNode Pattern
| Aspect | Benefit |
|--------|---------|
| **Query result** | Fully typed response data |
| **Variables** | Type-checked at compile time |
| **Fragments** | Types flow through fragment composition |
| **IDE support** | Autocomplete for fields and variables |
| **Refactoring** | Rename detection across operations |
- Generated by `@graphql-codegen/typed-document-node`
- Works with urql, Apollo Client, and other GraphQL clients
- Catches schema mismatches at compile time, not runtime
## Error Handling
| Error Type | Location | Cause |
|-----------|----------|-------|
| **GraphQL errors** | `response.data.mutation.errors[]` | Validation, permission, business logic |
| **Network errors** | Caught by client | Connection failure, timeout, 5xx |
| **Schema errors** | Build-time (codegen) | Operation doesn't match schema |
### Saleor Mutation Error Structure
| Field | Type | Description |
|-------|------|-------------|
| `field` | `String` | Which input field caused the error |
| `message` | `String` | Human-readable error message |
| `code` | `Enum` | Machine-readable error code |
- Always check `data.mutation.errors` after every mutation
- Map error codes to user-friendly messages in the storefront
## Client Libraries
| Client | Package | SSR Support | Caching | Best For |
|--------|---------|-------------|---------|----------|
| **urql** | `@urql/core`, `@urql/next` | Yes (via `@urql/next`) | Document cache, Graphcache | Saleor recommended |
| **Apollo Client** | `@apollo/client` | Yes | Normalized cache | Complex caching needs |
| **graphql-request** | `graphql-request` | N/A (no cache) | None | Simple scripts, server-side |
| **gql** (Python) | `gql` | N/A | None | Python scripts and tests |
- Include `Authorization: Bearer <token>` header for authenticated operations
- Include `saleor-channel: <slug>` header for channel-scoped queries
- For SSR: ensure proper request deduplication and cache hydration
## Operation Naming Conventions
| Convention | Example | Benefit |
|-----------|---------|---------|
| **Prefix with verb** | `GetProducts`, `CreateCheckout` | Clear intent |
| **Suffix queries** | `ProductListQuery`, `OrderDetailQuery` | Distinguish from mutations |
| **Suffix mutations** | `CheckoutCreateMutation` | Distinguish from queries |
| **Unique names** | No duplicates across codebase | Required by codegen |
## Pagination Patterns
Saleor uses Relay-style cursor-based pagination:
| Parameter | Type | Description |
|-----------|------|-------------|
| `first` | `Int` | Number of items from the start |
| `after` | `String` | Cursor after which to fetch |
| `last` | `Int` | Number of items from the end |
| `before` | `String` | Cursor before which to fetch |
### Response Structure
| Field | Path | Description |
|-------|------|-------------|
| **edges** | `connection.edges[]` | Array of edge objects |
| **node** | `edge.node` | The actual entity |
| **cursor** | `edge.cursor` | Opaque cursor string |
| **pageInfo.hasNextPage** | `connection.pageInfo` | More items forward |
| **totalCount** | `connection.totalCount` | Total items matching filter |
- Use `first` + `after` for forward pagination (most common)
- Avoid using `totalCount` for large datasets (can be slow)
## Introspection and Schema Downloading
| Method | Tool | Use Case |
|--------|------|----------|
| **Introspection query** | Built-in GraphQL client | Development exploration |
| **GraphQL Playground** | `/graphql/` in browser | Interactive schema browser |
| **Schema download** | `graphql-codegen` | CI/CD and type generation |
| **SDL export** | `rover graph introspect <url>` | Save schema as `.graphql` file |
## Testing GraphQL Operations
| Test Type | Tool | What to Test |
|-----------|------|-------------|
| **Unit** | Vitest, Jest | Operation result parsing, error mapping |
| **Integration** | Saleor test instance | Full round-trip query/mutation |
| **Type check** | `tsc --noEmit` | Generated types match operations |
| **Linting** | `@graphql-eslint/eslint-plugin` | Operation naming, fragment usage |
## Best Practices
- Use GraphQL code generation with TypedDocumentNode for end-to-end type safety
- Define reusable fragments for common field selections
- Always use variables for dynamic values — never concatenate strings
- Check `data.mutation.errors` after every mutation call
- Name every operation uniquely with descriptive PascalCase names
- Use cursor-based pagination with `first`/`after` for list queries
- Include the `saleor-channel` header for channel-scoped operations
- Keep operations minimal — request only the fields you need
- Run `graphql-codegen` in CI to catch schema mismatches
Fetch the GraphQL documentation for current Saleor schema, code generation setup, and client library configuration before implementing.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!