Skills apollo-client
install
source · Clone the upstream repo
git clone https://github.com/TerminalSkills/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/TerminalSkills/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/apollo-client" ~/.claude/skills/terminalskills-skills-apollo-client && rm -rf "$T"
manifest:
skills/apollo-client/SKILL.mdsource content
Apollo Client — GraphQL Client for React
You are an expert in Apollo Client, the comprehensive GraphQL client for React applications. You help developers fetch data with GraphQL queries and mutations, manage local and remote state with Apollo's normalized cache, implement optimistic UI updates, handle pagination, and configure authentication — providing a complete data management solution for GraphQL-powered apps.
Core Capabilities
Setup and Queries
import { ApolloClient, InMemoryCache, ApolloProvider, gql, useQuery, useMutation } from "@apollo/client"; const client = new ApolloClient({ uri: "https://api.example.com/graphql", cache: new InMemoryCache({ typePolicies: { Query: { fields: { posts: { keyArgs: ["filter"], merge(existing = [], incoming) { return [...existing, ...incoming]; } }, }, }, }, }), headers: { Authorization: `Bearer ${getToken()}` }, }); const GET_POSTS = gql` query GetPosts($limit: Int!, $offset: Int!, $filter: PostFilter) { posts(limit: $limit, offset: $offset, filter: $filter) { id title excerpt author { id name avatar } createdAt } } `; function PostList({ filter }: { filter?: PostFilter }) { const { data, loading, error, fetchMore } = useQuery(GET_POSTS, { variables: { limit: 10, offset: 0, filter }, }); if (loading) return <Skeleton />; if (error) return <Error message={error.message} />; return ( <div> {data.posts.map(post => <PostCard key={post.id} post={post} />)} <button onClick={() => fetchMore({ variables: { offset: data.posts.length } })}> Load more </button> </div> ); }
Mutations with Optimistic Updates
const CREATE_POST = gql` mutation CreatePost($input: CreatePostInput!) { createPost(input: $input) { id title excerpt author { id name } createdAt } } `; function CreatePostForm() { const [createPost, { loading }] = useMutation(CREATE_POST, { optimisticResponse: (vars) => ({ createPost: { __typename: "Post", id: "temp-id", title: vars.input.title, excerpt: vars.input.body.slice(0, 200), author: { __typename: "User", id: currentUser.id, name: currentUser.name }, createdAt: new Date().toISOString(), }, }), update(cache, { data: { createPost } }) { cache.modify({ fields: { posts(existing = []) { const ref = cache.writeFragment({ data: createPost, fragment: POST_FRAGMENT }); return [ref, ...existing]; }, }, }); }, }); const handleSubmit = (data) => createPost({ variables: { input: data } }); return <Form onSubmit={handleSubmit} loading={loading} />; }
Authentication
import { ApolloClient, createHttpLink, ApolloLink } from "@apollo/client"; import { setContext } from "@apollo/client/link/context"; import { onError } from "@apollo/client/link/error"; const httpLink = createHttpLink({ uri: "/graphql" }); const authLink = setContext((_, { headers }) => ({ headers: { ...headers, authorization: `Bearer ${localStorage.getItem("token")}` }, })); const errorLink = onError(({ graphQLErrors, networkError }) => { if (graphQLErrors?.some(e => e.extensions?.code === "UNAUTHENTICATED")) { localStorage.removeItem("token"); window.location.href = "/login"; } }); const client = new ApolloClient({ link: ApolloLink.from([errorLink, authLink, httpLink]), cache: new InMemoryCache(), });
Installation
npm install @apollo/client graphql
Best Practices
- Normalized cache — Apollo normalizes data by
; updates to one entity propagate everywhere__typename:id - Optimistic updates — Provide
for mutations; UI updates instantly, corrects on server responseoptimisticResponse - Type policies — Configure
for pagination merging, field read/write policiestypePolicies - Code generation — Use
to generate TypeScript types from your schema; fully typed queriesgraphql-codegen - Error link — Use
link for global error handling (auth refresh, logging, retry)onError - Fragments — Define reusable fragments for entity fields; share between queries and mutations
- Cache updates — Use
function orupdate
after mutations; prefer cache.modify for performancerefetchQueries - Polling and subscriptions — Use
for simple real-time, WebSocket subscriptions for true real-timepollInterval