Agent Skills: Apollo Client 3.10

This skill should be used when writing or modifying GraphQL operations, hooks, or mutations using Apollo Client 3.10. It enforces best practices for optimistic responses, cache updates, and TypeScript type generation. Use this skill when creating new queries/mutations, reviewing Apollo code, or troubleshooting cache issues.

UncategorizedID: codyswanngt/lisa/apollo-client

Install this agent skill to your local

pnpm dlx add-skill https://github.com/CodySwannGT/lisa/tree/HEAD/plugins/lisa-expo/skills/apollo-client

Skill Files

Browse the full folder contents for apollo-client.

Download Skill

Loading file tree…

plugins/lisa-expo/skills/apollo-client/SKILL.md

Skill Metadata

Name
apollo-client
Description
This skill should be used when writing or modifying GraphQL operations, hooks, or mutations using Apollo Client 3.10. It enforces best practices for optimistic responses, cache updates, and TypeScript type generation. Use this skill when creating new queries/mutations, reviewing Apollo code, or troubleshooting cache issues.

Apollo Client 3.10

Overview

This skill provides best practices for Apollo Client 3.10 in this codebase, ensuring consistent patterns for GraphQL operations, optimistic UI updates, cache management, and TypeScript type safety.

Quick Reference

Generator Commands

After modifying any operations.graphql file, run the appropriate generator:

bun run generate:types:dev        # Development environment
bun run generate:types:staging    # Staging environment
bun run generate:types:production # Production environment

Note: Replace bun with your project's package manager (npm, yarn, pnpm) as needed.

Import Pattern

All GraphQL types, hooks, and documents must come from generated types:

import {
  useGetPlayerQuery,
  useUpdatePlayerMutation,
  GetPlayerQuery,
  PlayerFragment,
  ListPlayersDocument,
} from "@/generated/graphql";

Core Rules

1. Only Use Generated Types

Import all GraphQL-related types from @/generated/graphql. Never define manual TypeScript types for GraphQL entities.

// CORRECT
import { PlayerFragment, useUpdatePlayerMutation } from "@/generated/graphql";

// INCORRECT - Never do this
type Player = { id: string; name: string };

2. Never Modify Generated Files

The generated/graphql.ts file is auto-generated by codegen. To change types:

  1. Edit the appropriate operations.graphql file in the feature directory
  2. Run bun run generate:types:dev
  3. Import the newly generated types

3. Always Run Generator After Schema Changes

After modifying any operations.graphql file, immediately run the generator before committing. Verify changes compile with bun run typecheck.

4. Always Include Optimistic Response

Every mutation must include an optimisticResponse for instant UI feedback:

const [updatePlayer] = useUpdatePlayerMutation({
  optimisticResponse: variables => ({
    __typename: "Mutation",
    updatePlayer: {
      __typename: "Player",
      id: variables.id,
      name: variables.input.name,
      updatedAt: new Date().toISOString(),
    },
  }),
});

Key requirements:

  • Always include __typename for every object in the response
  • Always include id for cache normalization
  • Use temporary IDs for new objects (e.g., crypto.randomUUID())
  • Include all fields that the mutation returns

5. Always Update Cache

Every mutation must handle cache updates using one of these strategies:

Automatic Updates - When mutation returns the full entity with id and __typename, Apollo updates automatically. No extra code needed.

cache.modify - For adding/removing items from lists:

const [addPlayer] = useAddPlayerMutation({
  optimisticResponse: {
    /* ... */
  },
  update(cache, { data }) {
    cache.modify({
      fields: {
        players(existingPlayers = [], { readField }) {
          const newRef = cache.writeFragment({
            data: data.addPlayer,
            fragment: PlayerFragmentDoc,
          });
          return [...existingPlayers, newRef];
        },
      },
    });
  },
});

refetchQueries - Fallback for complex scenarios:

const [complexMutation] = useComplexMutation({
  refetchQueries: ["ListPlayers"],
  awaitRefetchQueries: true,
});

Operations.graphql Structure

Fragment-First Pattern

Define fragments before queries/mutations that use them:

# 1. Fragments first
fragment PlayerFragment on Player {
  id
  knownName
  firstName
  lastName
  team {
    id
    name
  }
}

# 2. Queries second
query GetPlayer($id: ID!) {
  player(id: $id) {
    ...PlayerFragment
  }
}

# 3. Mutations last
mutation UpdatePlayer($id: ID!, $input: UpdatePlayerInput!) {
  updatePlayer(id: $id, input: $input) {
    ...PlayerFragment
  }
}

Include Required Fields

Mutations must return all fields needed for cache updates:

mutation AddPlayerToKanban($input: AddPlayerToKanbanInput!) {
  addPlayerToKanban(input: $input) {
    id # Required for cache normalization
    position
    notes
    kanbanPhaseId
    kanbanPhase {
      # Include related objects
      id
      name
    }
    createdAt
    updatedAt
  }
}

Query Best Practices

Fetch Policies

// Frequently changing data - balance speed and freshness
fetchPolicy: "cache-and-network";

// Stable reference data - prioritize cache
fetchPolicy: "cache-first";

// Always-fresh data - skip cache
fetchPolicy: "network-only";

Skip When Variables Undefined

const { data } = useGetPlayerQuery({
  variables: { id: playerId! },
  skip: !playerId,
});

Error Handling

Use onError callback instead of try/catch with console.log:

const [mutation] = useMutation(MUTATION, {
  onError: error => {
    setErrorState("Failed to update. Please try again.");
  },
});

Complete Mutation Pattern

Reference references/mutation-patterns.md for comprehensive examples of the complete mutation pattern including optimistic responses, cache updates, and error handling.

Validation Checklist

When writing or reviewing Apollo code, verify:

  • [ ] All types imported from @/generated/graphql
  • [ ] No manual type definitions for GraphQL entities
  • [ ] Every mutation has optimisticResponse
  • [ ] Every mutation has cache update strategy
  • [ ] __typename included in all optimistic response objects
  • [ ] id included in all optimistic response objects
  • [ ] Queries use appropriate fetchPolicy
  • [ ] Queries use skip when variables may be undefined
  • [ ] Error handling via onError callback
  • [ ] Generator was run after operations.graphql changes