# Apollo Graphql > Apollo Client is a GraphQL state management library for JavaScript that manages both local and remote data. The library provides built-in React integration and supports modern development practices wi --- # Apollo Client (React) - Documentation Source: https://www.apollographql.com/docs/react/ ## Overview Apollo Client is a GraphQL state management library for JavaScript that manages both local and remote data. The library provides built-in React integration and supports modern development practices with strong developer experience features. ## Core Capabilities The platform emphasizes several fundamental strengths: - **Data Fetching:** Write a query and receive data without manually tracking loading states - **Caching:** Normalized request/response caching boosts performance through local data responses - **Developer Tools:** Integrated support for TypeScript, Chrome/Firefox DevTools, and VS Code - **Modern React:** Full compatibility with hooks and Suspense patterns - **Flexibility:** Incrementally adoptable into existing JavaScript or TypeScript applications ## Key Documentation Areas ### Fundamental Concepts - **Queries:** Fetching and rendering data through GraphQL queries - **Fragments:** Building reusable, component-specific data queries - **Mutations:** Modifying server data with GraphQL operations - **Subscriptions:** Real-time updates via GraphQL subscriptions ### Data Management - **Caching:** Normalized cache prevents redundant network requests - **Local State:** Consolidated state management for both remote and local data - **Error Handling:** Comprehensive error management strategies ### Technical Integration - **Networking:** Custom headers, authentication, and HTTP configuration - **Testing:** Server-independent GraphQL operation testing - **Performance:** Response caching, query optimization, and bundle size reduction ## Platform Integration Apollo Client integrates with GraphOS features including `@defer` directives for incremental field data, subscription support, and persisted query safelisting for enhanced security. ## Community Support The library maintains integrations with Vue, Angular, Svelte, Web Components, and native mobile platforms (iOS/Kotlin), ensuring broad ecosystem compatibility. --- # Apollo Client Caching: Comprehensive Documentation Source: https://www.apollographql.com/docs/react/caching/overview ## Overview Apollo Client implements a sophisticated local caching mechanism through its `InMemoryCache`, which stores GraphQL query results in a "normalized, in-memory cache." This architecture enables rapid response to subsequent queries without network requests. ### Core Benefits The caching system provides: - **Immediate responses** to queries for already-cached data - **Reduced network traffic** through intelligent cache reuse - **Local state management** capabilities - **Automatic data deduplication** via normalization --- ## How Data Storage Works ### Flat Lookup Table Architecture Apollo Client organizes cached data as a flat lookup table of interconnected objects. While GraphQL responses often feature deeply nested structures, the cache flattens this hierarchy to optimize reads and updates. **Example Response Structure:** ```json { "data": { "person": { "__typename": "Person", "id": "cGVvcGxlOjE=", "name": "Luke Skywalker", "homeworld": { "__typename": "Planet", "id": "cGxhbmV0czox", "name": "Tatooine" } } } } ``` This nested response contains two distinct objects that must be normalized before storage. --- ## Data Normalization Process Normalization transforms nested response data into a flat, referenceable format through four steps: ### Step 1: Identify Objects The cache recognizes all distinct objects in the response. From the example above, this includes: - One `Person` object (id: `cGVvcGxlOjE=`) - One `Planet` object (id: `cGxhbmV0czox`) ### Step 2: Generate Cache IDs For each object identified, the cache generates a unique cache ID. The default format concatenates `__typename` and `id` (or `_id`) fields with a colon separator: - `Person:cGVvcGxlOjE=` - `Planet:cGxhbmV0czox` **Note:** Objects lacking `id` or `_id` fields are cached directly within their parent, making the cache partially nested for those entries. Custom cache ID formats can be configured for specific types. ### Step 3: Replace Object Fields with References Nested object fields become reference pointers to their normalized counterparts: **Before normalization:** ```json { "__typename": "Person", "id": "cGVvcGxlOjE=", "name": "Luke Skywalker", "homeworld": { "__typename": "Planet", "id": "cGxhbmV0czox", "name": "Tatooine" } } ``` **After normalization:** ```json { "__typename": "Person", "id": "cGVvcGxlOjE=", "name": "Luke Skywalker", "homeworld": { "__ref": "Planet:cGxhbmV0czox" } } ``` This approach enables multiple objects to reference the same cached entity without duplication. ### Step 4: Store Normalized Objects Objects are deposited into the flat lookup table. When an incoming object shares a cache ID with an existing cached object, their fields merge according to these rules: - **Incoming data overwrites** cached values for shared fields - **Preserved fields** include those appearing in only the existing or only the incoming object This merging strategy keeps local data synchronized as application state evolves. --- ## Practical Normalization Example Consider a SWAPI API query: ```graphql query { allPeople(first: 3) { people { id name homeworld { id name } } } } ``` This returns three `Person` objects with corresponding `Planet` objects. If two people share the same homeworld, the cache stores only one `Planet` reference, with both people pointing to it via `__ref`. **Result:** - 3 cached `Person` objects - 2 cached `Planet` objects (not 3, due to deduplication) - Multiple references to the single shared planet instance This normalization dramatically reduces memory usage and ensures consistency when planet data updates. --- ## Cache Visualization The **Apollo Client Devtools** browser extension provides a Cache inspector displaying: - All normalized objects in the cache - Reference relationships between objects - Individual field values and types - Real-time cache state changes This visual representation helps developers understand cache structure and debug caching behavior. --- ## Key Caching Features ### Automatic `__typename` Addition Apollo Client automatically includes `__typename` fields in queries even when not explicitly requested. This enables the normalization process and type identification. ### Reference System The `__ref` field notation indicates cache references: ```json {"__ref": "TypeName:cacheId"} ``` ### ROOT_QUERY Object The cache maintains a special `ROOT_QUERY` object that tracks top-level query results and their relationships to normalized objects. --- ## Configuring Cache Behavior Beyond default configuration, Apollo Client supports: - **Custom cache ID formats** for specific object types - **Field-level behavior customization** through field policies - **Local-only fields** for client state management - **Cache persistence** and hydration strategies - **Garbage collection** and memory management --- ## Next Steps for Implementation Developers should proceed to: 1. **Cache Configuration** — Learn specific configuration options for `InMemoryCache` 2. **Reading and Writing** — Master direct cache interaction patterns 3. **Local State Management** — Leverage the cache for application state 4. **Garbage Collection** — Understand automatic cleanup and eviction policies --- ## Summary Apollo Client's normalization strategy transforms nested GraphQL responses into a flat, reference-based cache structure. This design optimizes query performance, reduces data duplication, and enables sophisticated local state management. Understanding normalization is fundamental to leveraging Apollo Client's caching capabilities effectively. --- # Apollo Client Get Started Guide Source: https://www.apollographql.com/docs/react/get-started ## Overview Apollo Client is a comprehensive JavaScript library for managing GraphQL data in applications. This guide walks through initial setup, dependency installation, client initialization, React integration, and executing your first data queries. ## Step 1: Project Setup Create a new React project using either: - **Vite**: Local development environment - **CodeSandbox**: Cloud-based development sandbox ## Step 2: Installing Required Packages Three core packages are essential: 1. **@apollo/client** - "This single package contains virtually everything you need to set up Apollo Client" 2. **graphql** - Provides GraphQL query parsing logic 3. **rxjs** - Supplies the Observable primitive used throughout the library Install via npm: ```bash npm install @apollo/client graphql rxjs ``` The tutorial uses the FlyBy GraphQL API endpoint for demonstration purposes. ## Step 3: ApolloClient Initialization ### Import Required Symbols ```javascript import { ApolloClient, HttpLink, InMemoryCache, gql } from "@apollo/client"; import { ApolloProvider } from "@apollo/client/react"; ``` ### Create Client Instance ```javascript const client = new ApolloClient({ link: new HttpLink({ uri: "https://flyby-router-demo.herokuapp.com/" }), cache: new InMemoryCache(), }); ``` **Configuration explanation:** - **link**: Apollo Link that executes GraphQL operations against your server via HttpLink - **cache**: InMemoryCache instance for storing fetched results ### Test with Plain JavaScript ```javascript client .query({ query: gql` query GetLocations { locations { id name description photo } } `, }) .then((result) => console.log(result)); ``` ## Step 4: React Integration with ApolloProvider Wrap your application with ApolloProvider near the root level: ```javascript import React from "react"; import * as ReactDOM from "react-dom/client"; import { ApolloClient, InMemoryCache } from "@apollo/client"; import { ApolloProvider } from "@apollo/client/react"; import App from "./App"; const client = new ApolloClient({ uri: "https://flyby-router-demo.herokuapp.com/", cache: new InMemoryCache(), }); const root = ReactDOM.createRoot(document.getElementById("root")); root.render( ); ``` ## Step 5: Fetching Data with useQuery Hook ### Define Your Query ```javascript import { gql } from "@apollo/client"; import { useQuery } from "@apollo/client/react"; const GET_LOCATIONS = gql` query GetLocations { locations { id name description photo } } `; ``` ### Create Display Component ```javascript function DisplayLocations() { const { loading, error, data } = useQuery(GET_LOCATIONS); if (loading) return

Loading...

; if (error) return

Error : {error.message}

; return data.locations.map(({ id, name, description, photo }) => (

{name}

location-reference
About this location:

{description}


)); } ``` ### Hook Return Values The `useQuery` hook returns an object with: - **loading**: Boolean tracking query execution state - **error**: Contains error details if the query fails - **data**: The actual query results once available - **dataState**: Additional state information ### Integrate into App ```javascript export default function App() { return (

My first Apollo app 🚀


); } ``` ## Next Learning Steps After mastering basics, explore: - **Queries**: Advanced query patterns with arguments - **Fragments**: Data masking and component-driven architecture - **Mutations**: Writing and updating data - **TypeScript**: Adding type safety - **API Reference**: Direct client access patterns --- **Note**: Complete working examples are available on CodeSandbox for reference and comparison during development. --- # Apollo Client Mutations: Comprehensive Guide Source: https://www.apollographql.com/docs/react/data/mutations ## Overview Mutations enable you to modify backend data using GraphQL. Apollo Client's `useMutation` hook provides the primary API for executing mutations in React applications, allowing developers to send updates to GraphQL servers and manage the resulting state changes. ## Core Concepts ### The useMutation Hook The `useMutation` hook accepts a GraphQL mutation document and returns a tuple containing: 1. **Mutate function**: Called to execute the mutation (not automatic like `useQuery`) 2. **Status object**: Contains `data`, `loading`, `error`, and other fields tracking execution state ```javascript const [mutate, { data, loading, error }] = useMutation(MUTATION_DOCUMENT); ``` ### Key Differences from useQuery Unlike `useQuery`, mutations do not execute automatically on component render. Instead, you explicitly call the mutate function in response to user actions, typically form submissions. ## Executing Mutations ### Basic Example ```javascript const ADD_TODO = gql` mutation AddTodo($type: String!) { addTodo(type: $type) { id type } } `; function AddTodo() { const [addTodo, { loading, error }] = useMutation(ADD_TODO); return (
{ e.preventDefault(); addTodo({ variables: { type: "groceries" } }); }}>
); } ``` ### Providing Options Options can be supplied to `useMutation` directly or to the mutate function call. When provided to both, the mutate function's values take precedence, with variables being shallowly merged. ```javascript const [addTodo] = useMutation(ADD_TODO, { variables: { type: "default" } }); // Call with additional/override variables addTodo({ variables: { type: "custom" } }); ``` ## Tracking Mutation Status The returned status object includes fields for monitoring execution: - **`loading`**: Boolean indicating if mutation is in flight - **`error`**: Contains either `graphQLErrors` array or `networkError` - **`called`**: Boolean indicating if mutate function was invoked - **`data`**: Mutation result data ```javascript if (loading) return "Submitting..."; if (error) return `Error: ${error.message}`; ``` ### Reset Function The `reset()` function restores the mutation's result to its initial state, useful for dismissing error messages or clearing completed state: ```javascript const [login, { error, reset }] = useMutation(LOGIN_MUTATION); {error && ( reset()} /> )} ``` ## Updating Local Data ### Strategy Overview After mutation execution, update cached data using these approaches: 1. **Refetch queries**: Request updated data from the server 2. **Direct cache update**: Modify cache manually without additional requests 3. **Combined approach**: Update cache then optionally refetch for validation ### Refetching Queries Specify queries to refetch after mutation completes: ```javascript const [addTodo] = useMutation(ADD_TODO, { refetchQueries: [ GET_TODOS, // DocumentNode object "GetComments", // Query name string { query: GET_TODOS, variables: { id: 1 } } ] }); ``` Special refetch values: - `"active"`: Refetch all active queries - `"all"`: Refetch all active and inactive queries ### Direct Cache Updates The `update` function allows manual cache modifications after mutations complete. This approach provides "immediate" UI updates without network requests: ```javascript const [addTodo] = useMutation(ADD_TODO, { update(cache, { data: { addTodo } }) { cache.modify({ fields: { todos(existingTodos = []) { const newTodoRef = cache.writeFragment({ data: addTodo, fragment: gql` fragment NewTodo on Todo { id type } ` }); return [...existingTodos, newTodoRef]; } } }); } }); ``` **Important**: The `update` function executes twice if an optimistic response is provided—once with optimistic data, once with actual server response. ### Combining Update with Refetch Validation Use `onQueryUpdated` to refetch affected queries after cache updates, ensuring accuracy: ```javascript addTodo({ variables: { type: value }, update(cache, result) { // Manual cache modifications }, onQueryUpdated(observableQuery) { return shouldRefetch(observableQuery) ? observableQuery.refetch() : undefined; } }); ``` ## Best Practices for Mutation Responses Mutations should return "all objects and fields that it modified." This enables Apollo Client to normalize and cache results appropriately. Example response structure: ```json { "__typename": "Todo", "id": "5", "type": "groceries" } ``` Apollo Client automatically adds `__typename` and caches the object using its `__typename` and `keyFields` configuration. ## useMutation API Reference ### Key Options | Option | Type | Purpose | |--------|------|---------| | `variables` | Object | GraphQL variables required by mutation | | `refetchQueries` | Array/Function | Queries to refetch after mutation | | `update` | Function | Manual cache update handler | | `optimisticResponse` | Object/Function | Immediate UI response before server reply | | `onCompleted` | Function | Callback on successful completion | | `onError` | Function | Callback on error | | `errorPolicy` | String | How to handle responses with errors | | `context` | Object | Apollo Link context values | | `fetchPolicy` | String | Cache behavior (`network-only` or `no-cache`) | | `awaitRefetchQueries` | Boolean | Wait for refetch completion | | `keepRootFields` | Boolean | Preserve ROOT_MUTATION cache fields | ### Result Properties | Property | Type | Purpose | |----------|------|---------| | `called` | Boolean | Mutate function was invoked | | `loading` | Boolean | Mutation in flight | | `error` | ErrorLike | Error object if mutation failed | | `data` | Object | Mutation result data | | `client` | ApolloClient | Apollo Client instance used | | `reset` | Function | Reset to initial state | ## Error Handling Configure error policies to control partial data handling: - **`none`** (default): Include errors and reject partial results - **`ignore`**: Return partial results, suppress errors - **`all`**: Return both errors and partial results ```javascript const [mutate] = useMutation(MUTATION, { errorPolicy: "all", onError(error) { console.log(error.graphQLErrors); console.log(error.networkError); } }); ``` ## Performance: Optimistic UI Provide immediate UI feedback before server response: ```javascript const [addTodo] = useMutation(ADD_TODO, { optimisticResponse: { addTodo: { __typename: "Todo", id: -1, type: inputValue } } }); ``` The optimistic response is cached immediately and replaced with actual server data when received. ## Common Patterns ### Form Submission ```javascript
{ e.preventDefault(); mutate({ variables: { /* form data */ } }); resetForm(); }}> ``` ### Post-Mutation Navigation ```javascript const [login] = useMutation(LOGIN, { onCompleted({ login }) { navigate("/dashboard"); } }); ``` ### Dependent Mutations Chain mutations using `onCompleted`: ```javascript const [createUser] = useMutation(CREATE_USER, { onCompleted(userData) { createProfile({ variables: { userId: userData.id } }); } }); ``` ## Integration with Caching Understanding Apollo Client's cache normalization is essential for effective mutation handling. Objects are cached by `__typename` and configured `keyFields`, enabling automatic cache updates when mutations return modified objects. For complex cache scenarios, the `cache.modify()` API provides granular control over normalized cache entries, field-by-field modifications, and reference management. --- **Related Topics**: [Optimistic mutation results](https://www.apollographql.com/docs/react/performance/optimistic-ui/), [Caching in Apollo Client](https://www.apollographql.com/docs/react/caching/overview), [Error handling](https://www.apollographql.com/docs/react/data/error-handling/) --- # Apollo Client Queries Documentation Source: https://www.apollographql.com/docs/react/data/queries ## Overview Apollo Client provides powerful hooks for executing GraphQL queries in React applications. The primary hook, `useQuery`, handles data fetching, caching, and state management automatically. ## Core Hooks ### useQuery The fundamental hook for executing queries automatically when a component renders. **Basic Usage:** ```javascript const { loading, error, data } = useQuery(GET_DOGS); if (loading) return "Loading..."; if (error) return `Error! ${error.message}`; return ; ``` **Key Features:** - Automatic query execution on component mount - Built-in loading and error state tracking - Integrated caching mechanism - Network status monitoring ### useLazyQuery For manually triggering queries in response to user interactions rather than automatic execution. **Usage Pattern:** ```javascript const [getDogs, { loading, error, data }] = useLazyQuery(GET_DOGS); return ( <> {data?.dogs.map(dog => )} ); ``` **Advantages:** - Deferred query execution - Execution function returns a promise - Useful for search, filters, and on-demand loading ## Query Options ### Fetch Policies Control how Apollo Client interacts with the cache: | Policy | Behavior | |--------|----------| | `cache-first` | Check cache first; fetch from network only if data missing (default) | | `cache-only` | Query cache exclusively; never contact server | | `network-only` | Always fetch from network; store results in cache | | `cache-and-network` | Query both cache and network simultaneously | | `no-cache` | Fetch from network without caching results | | `standby` | Use cache-first logic but don't auto-update on changes | ### nextFetchPolicy Specify different fetch behavior after the initial query execution: ```javascript const { data } = useQuery(GET_DOGS, { fetchPolicy: "network-only", nextFetchPolicy: "cache-first" }); ``` This pattern ensures fresh data on first load, then relies on cache for performance. ### Common Options | Option | Purpose | |--------|---------| | `variables` | Object containing GraphQL variables | | `pollInterval` | Milliseconds between automatic refetches (0 = disabled) | | `skip` | Boolean to skip query execution | | `errorPolicy` | How to handle responses with both errors and partial data | | `notifyOnNetworkStatusChange` | Trigger re-renders on network status changes | | `context` | Pass data through Apollo Link chain | ## Data Fetching Strategies ### Polling Automatically refresh data at regular intervals: ```javascript const { data } = useQuery(GET_DOG_PHOTO, { variables: { breed }, pollInterval: 500 // Refetch every 500ms }); ``` Control polling dynamically with `startPolling()` and `stopPolling()` functions returned by the hook. ### Refetching Manually trigger fresh data retrieval: ```javascript const { data, refetch } = useQuery(GET_DOG_PHOTO, { variables: { breed } }); ``` Pass new variables to refetch: ```javascript refetch({ breed: "dalmatian" }) ``` ### Pagination Implement incremental data loading with `fetchMore`: ```javascript const { fetchMore } = useQuery(GET_DOGS_PAGINATED); const loadMore = () => { fetchMore({ variables: { offset: currentOffset + pageSize }, updateQuery: (prev, { fetchMoreResult }) => { return { dogs: [...prev.dogs, ...fetchMoreResult.dogs] }; } }); }; ``` ## State Management ### Loading States The hook provides fine-grained network status tracking: ```javascript import { NetworkStatus } from "@apollo/client"; const { loading, networkStatus } = useQuery(QUERY); if (networkStatus === NetworkStatus.refetch) { return "Refetching..."; } ``` The `loading` property indicates any in-flight operation, while `networkStatus` offers granular operation type information. ### Error Handling Configure error behavior with `errorPolicy`: - `none` (default): Discard partial data on error - `all`: Return partial data alongside errors - `ignore`: Return data, suppress errors ```javascript const { data, error } = useQuery(QUERY, { errorPolicy: "all" }); ``` ### Data Completeness The `dataState` property indicates result status: - `empty`: No data available - `partial`: Incomplete data from cache - `streaming`: Deferred query still receiving data - `complete`: Fully satisfied result ## Advanced Features ### skipToken Type-safe query skipping mechanism: ```javascript import { skipToken, useQuery } from "@apollo/client"; const { data } = useQuery(query, userId ? { variables: { userId } } : skipToken); ``` This avoids TypeScript type errors when conditionally skipping queries. ### useLazyQuery Promise Handling Access results through returned promise: ```javascript const [getDogs] = useLazyQuery(GET_DOGS); const handleClick = async () => { const { data } = await getDogs(); // Process data }; ``` Handle errors based on `errorPolicy`: ```javascript try { const { data } = await getDogs(); } catch (error) { // Handle GraphQL or network errors } ``` ### Query Result Retention Keep queries running after component unmount: ```javascript const promise = getDogs(); promise.retain(); const { data } = await promise; ``` ## Performance Optimization ### Caching Benefits Apollo Client automatically caches results, providing instant responses for repeated queries without network requests. ### Variable Changes When query variables change, `fetchPolicy` resets to its initial value by default, triggering fresh network requests for `network-only` policies. ### Return Partial Data Enable partial results from cache: ```javascript const { data } = useQuery(QUERY, { returnPartialData: true }); ``` Useful for rendering incomplete data while waiting for full results. ## Result Object Properties ### Data Properties - `data`: Query result (may be partial based on `dataState`) - `previousData`: Result from previous execution - `variables`: Variables used in query - `dataState`: Completeness indicator ### Network Properties - `loading`: Boolean indicating in-flight status - `networkStatus`: Granular operation state - `client`: ApolloClient instance reference ### Helper Functions - `refetch()`: Re-execute with optional new variables - `fetchMore()`: Pagination support - `startPolling(interval)`: Begin periodic updates - `stopPolling()`: End polling - `subscribeToMore()`: Subscribe to real-time updates - `updateQuery()`: Manually update cached result ## Best Practices 1. **Use appropriate fetch policies** based on data freshness requirements 2. **Configure `nextFetchPolicy`** for optimal cache usage after initial load 3. **Handle loading states explicitly** to provide user feedback 4. **Leverage `skipToken`** for type-safe conditional queries 5. **Use `refetch` and polling** judiciously to avoid excessive server load 6. **Implement error boundaries** around query execution for resilience 7. **Monitor `networkStatus`** for granular state updates beyond simple `loading` ## Related Documentation - [Mutations](https://www.apollographql.com/docs/react/data/mutations/) - [Subscriptions](https://www.apollographql.com/docs/react/data/subscriptions/) - [Caching](https://www.apollographql.com/docs/react/caching/overview/) - [Error Handling](https://www.apollographql.com/docs/react/data/error-handling/) - [Suspense Support](https://www.apollographql.com/docs/react/data/suspense/)