graphql-apollo-client

from pluginagentmarketplace/custom-plugin-graphql

GraphQL Development Plugin

1 stars0 forksUpdated Jan 5, 2026
npx skills add https://github.com/pluginagentmarketplace/custom-plugin-graphql --skill graphql-apollo-client

SKILL.md

Apollo Client Skill

Master GraphQL in React applications

Overview

Learn to integrate Apollo Client with React, including hooks, cache management, optimistic updates, and real-time subscriptions.


Quick Reference

HookPurposeReturns
useQueryFetch data{ data, loading, error, refetch }
useMutationModify data[mutate, { data, loading, error }]
useSubscriptionReal-time{ data, loading, error }
useLazyQueryOn-demand fetch[execute, { data, loading }]

Core Patterns

1. Client Setup

import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider,
  createHttpLink,
  from
} from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { onError } from '@apollo/client/link/error';

// HTTP connection
const httpLink = createHttpLink({
  uri: 'http://localhost:4000/graphql',
  credentials: 'include',
});

// Auth header
const authLink = setContext((_, { headers }) => ({
  headers: {
    ...headers,
    authorization: localStorage.getItem('token')
      ? `Bearer ${localStorage.getItem('token')}`
      : '',
  },
}));

// Error handling
const errorLink = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors) {
    graphQLErrors.forEach(({ message, extensions }) => {
      if (extensions?.code === 'UNAUTHENTICATED') {
        window.location.href = '/login';
      }
    });
  }
});

// Cache with type policies
const cache = new InMemoryCache({
  typePolicies: {
    User: { keyFields: ['id'] },
    Query: {
      fields: {
        users: {
          keyArgs: ['filter'],
          merge(existing, incoming, { args }) {
            if (!args?.after) return incoming;
            return {
              ...incoming,
              edges: [...(existing?.edges || []), ...incoming.edges],
            };
          },
        },
      },
    },
  },
});

// Client
const client = new ApolloClient({
  link: from([errorLink, authLink, httpLink]),
  cache,
});

// Provider
function App() {
  return (
    <ApolloProvider client={client}>
      <Router />
    </ApolloProvider>
  );
}

2. Queries

import { gql, useQuery } from '@apollo/client';

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

function UserProfile({ userId }) {
  const { data, loading, error, refetch } = useQuery(GET_USER, {
    variables: { id: userId },
    // Options
    fetchPolicy: 'cache-and-network',
    pollInterval: 60000, // Refetch every minute
    skip: !userId,       // Skip if no userId
  });

  if (loading) return <Spinner />;
  if (error) return <Error onRetry={refetch} />;

  return <div>{data.user.name}</div>;
}

// Pagination
function UserList() {
  const { data, fetchMore, networkStatus } = useQuery(GET_USERS, {
    variables: { first: 10 },
    notifyOnNetworkStatusChange: true,
  });

  const loadMore = () => {
    fetchMore({
      variables: { after: data.users.pageInfo.endCursor },
    });
  };

  return (
    <>
      {data?.users.edges.map(({ node }) => (
        <UserCard key={node.id} user={node} />
      ))}
      {data?.users.pageInfo.hasNextPage && (
        <button onClick={loadMore}>Load More</button>
      )}
    </>
  );
}

3. Mutations

const CREATE_USER = gql`
  mutation CreateUser($input: CreateUserInput!) {
    createUser(input: $input) {
      user { id name email }
      errors { field message }
    }
  }
`;

function CreateUserForm() {
  const [createUser, { loading }] = useMutation(CREATE_USER, {
    // Update cache after success
    update(cache, { data }) {
      if (!data?.createUser.user) return;

      cache.modify({
        fields: {
          users(existing = { edges: [] }) {
            const newRef = cache.writeFragment({
              data: data.createUser.user,
              fragment: gql`fragment NewUser on User { id name email }`,
            });
            return {
              ...existing,
              edges: [{ node: newRef }, ...existing.edges],
            };
          },
        },
      });
    },

    // Optimistic response
    optimisticResponse: (vars) => ({
      createUser: {
        __typename: 'CreateUserPayload',
        user: {
          __typename: 'User',
          id: 'temp-' + Date.now(),
          ...vars.input,
        },
        errors: [],
      },
    }),
  });

  const handleSubmit = async (input) => {
    const { data } = await createUser({ variables: { input } });
    if (data?.createUser.errors.length) {
      // Handle validation errors
    }
  };

  return <Form onSubmit={handleSubmit} loading={loading} />;
}

4. Optimistic Updates

// Delete
const [deleteUser] = useMutation(DELETE_USER, {
  optimisticResponse: {
    deleteUser: { success: true, id: userId },
  },
  update(cache, { data }) {
    cache.evict({ id: cache.identify({ __typename: 'User', id: userId }) });
    cache.gc();
  

...
Read full content

Repository Stats

Stars1
Forks0
LicenseOther