---
name: rover-operation-builder
description: Generate GraphQL operations (queries, mutations, subscriptions, fragments) using schemas fetched from Apollo GraphOS via Rover CLI. Use when the user wants to create GraphQL operations, write queries or mutations, build subscriptions, generate fragments, or needs help crafting GraphQL code based on their schema.
---

# Rover Operation Builder Skill

This skill helps you generate proper GraphQL operations by fetching and analyzing schemas from Apollo GraphOS using the Rover CLI.

## When to Use

Use this skill when the user wants to:
- Generate GraphQL queries, mutations, or subscriptions
- Create reusable GraphQL fragments
- Write operations based on their actual schema
- Understand what fields and types are available
- Build properly typed operations with correct arguments
- Get suggestions for related fields to include
- Validate operation syntax against their schema

## Overview

This skill combines Rover's schema fetching capabilities with GraphQL operation generation to ensure type-safe, schema-compliant operations.

**Workflow**:
1. Fetch the current schema from GraphOS using Rover
2. Parse the schema to understand available types, fields, and arguments
3. Generate operations based on the user's natural language description
4. Validate the operation against the schema
5. Suggest improvements and best practices

## Step 1: Fetch the Schema

Before generating operations, fetch the schema from GraphOS:

### For Graphs (Monographs)

```bash
# Fetch to stdout
rover graph fetch my-graph@production

# Save to file for analysis
rover graph fetch my-graph@production --output schema.graphql
```

### For Subgraphs (Federated)

```bash
# Fetch subgraph schema
rover subgraph fetch my-graph@production --name products

# Save to file
rover subgraph fetch my-graph@production --name products --output products-schema.graphql
```

### Caching Strategy

To avoid repeated fetches:
1. Save schema to a local file (e.g., `schema.graphql`)
2. Reuse the cached schema for operation generation
3. Refresh when the user indicates schema has changed
4. Store in `.claude/cache/` or project root

## Step 2: Parse the Schema

After fetching, analyze the SDL to identify:

**Type Definitions**:
- Object types
- Input types
- Enum types
- Interface types
- Union types
- Scalar types

**Root Types**:
- `Query` - Available read operations
- `Mutation` - Available write operations
- `Subscription` - Available real-time operations

**Field Information**:
- Field names and types
- Required vs optional fields
- Arguments (required/optional, types)
- Nullability
- Lists vs single values

## Step 3: Generate Operations

Create GraphQL operations based on user requests:

### Query Generation

**User request**: "Fetch all products with their name, price, and category"

**Analyze schema**:
```graphql
type Query {
  products: [Product!]!
}

type Product {
  id: ID!
  name: String!
  price: Float!
  category: Category!
  description: String
  inStock: Boolean!
}

type Category {
  id: ID!
  name: String!
}
```

**Generated operation**:
```graphql
query GetProducts {
  products {
    id
    name
    price
    category {
      id
      name
    }
  }
}
```

### Mutation Generation

**User request**: "Create a mutation to update a product's price"

**Analyze schema**:
```graphql
type Mutation {
  updateProduct(id: ID!, input: UpdateProductInput!): Product!
}

input UpdateProductInput {
  name: String
  price: Float
  description: String
}
```

**Generated operation**:
```graphql
mutation UpdateProductPrice($productId: ID!, $newPrice: Float!) {
  updateProduct(id: $productId, input: { price: $newPrice }) {
    id
    name
    price
    category {
      id
      name
    }
  }
}
```

### Subscription Generation

**User request**: "Subscribe to new product updates"

**Analyze schema**:
```graphql
type Subscription {
  productUpdated(categoryId: ID): Product!
}
```

**Generated operation**:
```graphql
subscription OnProductUpdated($categoryId: ID) {
  productUpdated(categoryId: $categoryId) {
    id
    name
    price
    inStock
    category {
      id
      name
    }
  }
}
```

### Fragment Generation

**User request**: "Create a reusable fragment for product details"

**Generated operation**:
```graphql
fragment ProductDetails on Product {
  id
  name
  price
  description
  inStock
  category {
    id
    name
  }
}

# Usage in query
query GetProducts {
  products {
    ...ProductDetails
  }
}
```

## Step 4: Operation Best Practices

When generating operations, follow these guidelines:

### Always Include IDs

```graphql
query GetProducts {
  products {
    id  # Always include ID for caching
    name
    price
  }
}
```

### Use Operation Names

```graphql
# Good
query GetProductById($id: ID!) {
  product(id: $id) {
    id
    name
  }
}

# Avoid
query {
  product(id: "123") {
    name
  }
}
```

### Use Variables for Arguments

```graphql
# Good
mutation UpdateProduct($id: ID!, $input: UpdateProductInput!) {
  updateProduct(id: $id, input: $input) {
    id
    name
  }
}

# Avoid
mutation {
  updateProduct(id: "123", input: { name: "New Name" }) {
    id
    name
  }
}
```

### Request Useful Fields

Suggest fields that are commonly needed:
- IDs for caching and references
- Display fields (name, title, etc.)
- Related objects that provide context
- Timestamps (createdAt, updatedAt)

### Handle Nested Types Appropriately

```graphql
query GetProduct($id: ID!) {
  product(id: $id) {
    id
    name
    category {
      id
      name
      # Include category fields users likely need
    }
    reviews {
      id
      rating
      comment
      author {
        id
        name
        # Don't nest too deeply unless requested
      }
    }
  }
}
```

## Step 5: Validation

Validate generated operations against the schema:

**Check for**:
- Field existence on types
- Correct argument names and types
- Required arguments are provided
- Proper nesting of selections
- Valid variable types
- Fragment type conditions match

**Common Issues**:

❌ Field doesn't exist:
```graphql
query {
  products {
    id
    cost  # Should be 'price'
  }
}
```

❌ Missing required argument:
```graphql
query {
  product {  # Missing required 'id' argument
    id
    name
  }
}
```

❌ Wrong variable type:
```graphql
mutation UpdateProduct($id: String!) {  # Should be ID!
  updateProduct(id: $id, input: { name: "New" }) {
    id
  }
}
```

## Common Patterns

### Pagination

```graphql
query GetProductsWithPagination($limit: Int!, $offset: Int!) {
  products(limit: $limit, offset: $offset) {
    id
    name
    price
  }
  productsCount
}
```

### Filtering

```graphql
query GetProductsByCategory($categoryId: ID!, $inStock: Boolean) {
  products(categoryId: $categoryId, inStock: $inStock) {
    id
    name
    price
    inStock
  }
}
```

### Sorting

```graphql
query GetProductsSorted($sortBy: ProductSortField!, $order: SortOrder!) {
  products(sortBy: $sortBy, order: $order) {
    id
    name
    price
  }
}
```

### Conditional Fragments

```graphql
query GetItems {
  items {
    id
    ... on Product {
      name
      price
    }
    ... on Service {
      name
      duration
    }
  }
}
```

### Aliases for Multiple Queries

```graphql
query GetMultipleProducts {
  product1: product(id: "1") {
    id
    name
  }
  product2: product(id: "2") {
    id
    name
  }
}
```

## Example Workflow

**User**: "Help me fetch all users with their recent orders"

**Steps**:

1. **Fetch schema** (if not cached):
```bash
rover graph fetch my-graph@production --output schema.graphql
```

2. **Analyze schema**:
```graphql
type Query {
  users: [User!]!
}

type User {
  id: ID!
  name: String!
  email: String!
  orders: [Order!]!
}

type Order {
  id: ID!
  total: Float!
  status: OrderStatus!
  createdAt: DateTime!
  items: [OrderItem!]!
}
```

3. **Generate operation**:
```graphql
query GetUsersWithRecentOrders {
  users {
    id
    name
    email
    orders {
      id
      total
      status
      createdAt
      items {
        id
        quantity
        product {
          id
          name
          price
        }
      }
    }
  }
}
```

4. **Suggest improvements**:
- "You might want to limit the number of orders per user"
- "Consider adding pagination for the orders list"
- "Add a filter for order status if you only want recent orders"

5. **Provide enhanced version**:
```graphql
query GetUsersWithRecentOrders($orderLimit: Int = 5, $orderStatus: [OrderStatus!]) {
  users {
    id
    name
    email
    orders(limit: $orderLimit, status: $orderStatus, orderBy: CREATED_AT_DESC) {
      id
      total
      status
      createdAt
      items {
        id
        quantity
        product {
          id
          name
          price
        }
      }
    }
  }
}
```

## Tips for Operation Generation

1. **Start with what the user explicitly requested**
2. **Add essential fields** (IDs, names, display fields)
3. **Suggest related fields** that might be useful
4. **Use variables** for dynamic values
5. **Name operations** descriptively
6. **Include fragments** for repeated selections
7. **Consider pagination** for list fields
8. **Validate against schema** before presenting
9. **Provide usage examples** with sample variables
10. **Suggest error handling** fields if available

## Handling Different Schema Patterns

### Relay-Style Connections

```graphql
query GetProductsConnection($first: Int!, $after: String) {
  products(first: $first, after: $after) {
    edges {
      cursor
      node {
        id
        name
        price
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

### Federation (Entities)

```graphql
query GetProductWithReviews($representations: [_Any!]!) {
  _entities(representations: $representations) {
    ... on Product {
      id
      name
      reviews {
        id
        rating
        comment
      }
    }
  }
}
```

### Interfaces and Unions

```graphql
query GetSearchResults($query: String!) {
  search(query: $query) {
    ... on Product {
      id
      name
      price
    }
    ... on Article {
      id
      title
      publishedAt
    }
    ... on User {
      id
      name
      email
    }
  }
}
```

## Error Handling

When schema fetch fails:
1. Check authentication (`APOLLO_KEY` or `rover config auth`)
2. Verify graph ref format (`graph-id@variant`)
3. Confirm graph/subgraph exists in GraphOS
4. Check network connectivity

When operation generation is unclear:
1. Ask clarifying questions about what data is needed
2. Show available types and fields from schema
3. Provide examples based on similar patterns
4. Offer multiple options if ambiguous

## Related Skills

- Use `rover-schema` skill to publish or check schemas
- Use `rover-dev` skill for local testing of operations
- Use `rover-supergraph` skill for federated schema composition

## Additional Resources

- GraphQL spec: https://spec.graphql.org/
- Apollo Client operations: https://www.apollographql.com/docs/react/data/queries
- Rover CLI: https://www.apollographql.com/docs/rover
- GraphQL best practices: https://graphql.org/learn/best-practices