Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 3.2.0 #6774

Merged
merged 115 commits into from
Sep 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
7112d03
feature: added support for automatic type inference with typed-docume…
dotansimha Jul 28, 2020
36dc45b
update typed-document-node to 1.0.0
dotansimha Jul 29, 2020
9614c65
update version, move to devDependency, added re-export
dotansimha Aug 4, 2020
c550dc3
update lockfile
dotansimha Aug 4, 2020
af18c78
Move TypedDocumentNode to src/core/types.ts.
benjamn Aug 4, 2020
2e0c725
More tests of TypedDocumentNode and cache.{read,write}{Query,Fragment}.
benjamn Aug 4, 2020
02528dd
Move @graphql-typed-document-node/core back to dependencies.
benjamn Aug 4, 2020
081e604
Merge pull request #6720 from dotansimha/feature/typed-document-node
benjamn Aug 4, 2020
c689897
Add beta tag to npm deploy script.
benjamn Aug 4, 2020
15d6324
Mention PR #6720 in CHANGELOG.md.
benjamn Aug 4, 2020
b883fc6
Bump @apollo/client npm version to 3.2.0-beta.0.
benjamn Aug 4, 2020
96f86d2
Bump `@graphql-typed-document-node/core` to v3 (#6778)
dotansimha Aug 5, 2020
e62c734
Merge branch 'master' into release-3.2
benjamn Aug 6, 2020
6577c4a
Bump @apollo/client npm version to 3.2.0-beta.1.
benjamn Aug 6, 2020
46dd608
Disable feud-stopping logic after any cache eviction. (#6817)
benjamn Aug 10, 2020
fe590bc
Bump @apollo/client npm version to 3.2.0-beta.2.
benjamn Aug 10, 2020
2839ee4
Merge branch 'master' into release-3.2
benjamn Aug 17, 2020
c7b3ccd
Set result.partial only if true in getCurrentResult.
benjamn Aug 14, 2020
1dd9301
Simplify fetchMore loading result simulation.
benjamn Aug 14, 2020
97f3caf
Avoid full reobservation for broadcasts from optimistic transactions.
benjamn Aug 14, 2020
44a5f13
Fix optimistic mutation tests, again.
benjamn Aug 17, 2020
8bb4820
Make it clearer that saveAsLastResult defaults to true.
benjamn Aug 17, 2020
e64b642
Keep ObservableQuery#observe private for now.
benjamn Aug 18, 2020
d61fa8a
Mention PR #6854 in CHANGELOG.md.
benjamn Aug 18, 2020
9866ead
Merge pull request #6854 from apollographql/avoid-full-reobservation-…
benjamn Aug 18, 2020
2e2c645
Merge branch 'master' into release-3.2.
benjamn Aug 18, 2020
ac7717a
Bump @apollo/client npm version to 3.2.0-beta.3.
benjamn Aug 18, 2020
d183c22
Use context to track whether reading within @client subtree.
benjamn Aug 19, 2020
5023915
Merge branch 'master' into release-3.2.
benjamn Aug 20, 2020
45179b9
Generalize listening API for reactive variables.
benjamn Aug 20, 2020
2f494c8
Implement useReactiveVar hook.
benjamn Aug 20, 2020
141794c
Mention PR #6867 in CHANGELOG.md.
benjamn Aug 20, 2020
002e199
Docs for useReactiveVar.
benjamn Aug 20, 2020
b9382b0
Avoid visiting new listeners added by other listeners.
benjamn Aug 20, 2020
b874104
Store broadcastable caches separately from listeners.
benjamn Aug 20, 2020
83e2c1b
Merge pull request #6867 from apollographql/useReactiveVar
benjamn Aug 20, 2020
d89d728
Bump @apollo/client npm version to 3.2.0-beta.4.
benjamn Aug 20, 2020
583f62b
Throw when writeFragment cannot identify object
Aug 18, 2020
112228f
Warn if object cannot be identified
Aug 20, 2020
a2f90df
Add stringified result to error message
Aug 21, 2020
ea5a356
Mention PR #6859 in CHANGELOG.md.
benjamn Aug 21, 2020
766d3ff
Merge pull request #6859 from apollographql/writeFragment-identity-error
benjamn Aug 21, 2020
24a4396
Check structural equality in QueryInfo#setDiff. (#6891)
benjamn Aug 24, 2020
c4d100f
Use nextFetchPolicy when polling to restore original policy.
benjamn Aug 24, 2020
0bacd98
Use nextFetchPolicy in ObservableQuery#{refetch,setVariables}, too.
benjamn Aug 24, 2020
1ae25cc
Allow options.nextFetchPolicy to be a function.
benjamn Aug 24, 2020
f38d259
Mention PR #6893 in CHANGELOG.md.
benjamn Aug 25, 2020
03ee726
Merge pull request #6893 from apollographql/nextFetchPolicy-improvements
benjamn Aug 25, 2020
14091ce
Bump @apollo/client npm version to 3.2.0-beta.5.
benjamn Aug 25, 2020
00c4a13
Consider cache.modify a destructive method, like cache.evict.
benjamn Aug 25, 2020
889d103
Mention PR #6898 in CHANGELOG.md.
benjamn Aug 25, 2020
53455f5
Regression test for PRs #6898 and #6817.
benjamn Aug 25, 2020
5b9581b
Merge pull request #6898 from apollographql/consider-cache.modify-des…
benjamn Aug 25, 2020
75499a7
Merge branch 'main' into release-3.2.
benjamn Aug 25, 2020
cb46484
Bump @apollo/client npm version to 3.2.0-beta.6.
benjamn Aug 25, 2020
aae3a1e
Merge branch 'main' into release-3.2.
benjamn Aug 27, 2020
95d2a75
Bump @apollo/client npm version to 3.2.0-beta.7.
benjamn Aug 27, 2020
1a601d8
Ensure cache.{evict,modify} not wrapped more than once.
benjamn Aug 28, 2020
ab5a4f0
Better type inference for {Query,Subscription,Mutation}.propTypes.
benjamn Aug 28, 2020
4908ad7
Bump @apollo/client npm version to 3.2.0-beta.8.
benjamn Aug 28, 2020
c2ef68f
Revert "Check structural equality in QueryInfo#setDiff. (#6891)"
benjamn Aug 28, 2020
0c04a83
Bump @apollo/client npm version to 3.2.0-beta.9.
benjamn Aug 28, 2020
e52d0fb
Merge branch 'main' into release-3.2.
benjamn Aug 30, 2020
d3d4b3b
Hoist shared details out of EntityStore#modify forEach loop.
benjamn Aug 27, 2020
558d1ef
Allow cache.modify to invalidate fields without altering them.
benjamn Aug 27, 2020
8911805
Provide options.storage to cache.modify functions, too.
benjamn Aug 22, 2020
a8758de
Never let options.storage be null.
benjamn Sep 8, 2020
47c00e7
Make EntityStore.Root responsible for options.storage management.
benjamn Sep 8, 2020
bd66129
Add more tests of options.storage, including cache.modify.
benjamn Sep 8, 2020
95f1a6f
Bump bundlesize limit to 24.7kB.
benjamn Sep 8, 2020
59d5940
Mention PR #6991 in CHANGELOG.md.
benjamn Sep 8, 2020
d1fceb6
Documentation for cache.modify details.INVALIDATE sentinel.
benjamn Sep 8, 2020
2c15bb4
Mention details.INVALIDATE in cache.modify API docs.
benjamn Sep 8, 2020
6e3c999
Merge pull request #6991 from apollographql/cache.modify-invalidation
benjamn Sep 8, 2020
f4d214b
Merge branch 'main' into release-3.2.
benjamn Sep 8, 2020
e086a40
Bump @apollo/client npm version to 3.2.0-beta.10.
benjamn Sep 8, 2020
7c06ad2
Merge branch 'main' into release-3.2.
benjamn Sep 9, 2020
c4a09b7
Eliminate unnecessary StoreReader#readQueryFromStore method.
benjamn Aug 20, 2020
065d317
Use getFragmentFromSelection helper in executeSelectionSet.
benjamn Aug 22, 2020
990a488
Invert storage of subtype-supertype relationships in Policies class.
benjamn Aug 21, 2020
1c54969
Bring back heuristic fragment matching, with a twist.
benjamn Aug 22, 2020
92a04db
Return early when inexact fragment type condition is unknown.
benjamn Aug 22, 2020
fcbc86f
Check selectionSetMatchesResult before checking fuzzy subtypes.
benjamn Aug 26, 2020
ae4a6f5
Add more tests of possibleTypes and fragmentMatches.
benjamn Sep 10, 2020
02b0ac8
Mention PR #6901 in CHANGELOG.md.
benjamn Sep 10, 2020
4a22dcb
Merge pull request #6901 from apollographql/heuristic-fragment-matchi…
benjamn Sep 10, 2020
0d510d4
Bump @apollo/client npm version to 3.2.0-beta.11.
benjamn Sep 10, 2020
ccb0a79
Remove invariant forbidding cache-only FetchPolicy in refetch.
benjamn Sep 10, 2020
59e9049
Initialize ObservableQuery in updateObservableQuery even if skip is t…
mu29 Sep 10, 2020
7e94986
Merge branch 'main' into release-3.2.
benjamn Sep 10, 2020
09c0249
Update CHANGELOG.md for recent release-3.2 changes.
benjamn Sep 10, 2020
cd6ff47
Bump @apollo/client npm version to 3.2.0-beta.12.
benjamn Sep 10, 2020
0c98c59
Add new persisted-queries deps
hwillson Aug 14, 2020
4029053
Initial persisted-queries code migration with modifications
hwillson Aug 14, 2020
ad01106
Add the persisted-queries entry point
hwillson Aug 14, 2020
b951c8f
Add @apollo/client/link/persisted-queries to the exports test
hwillson Aug 14, 2020
e255e76
Make `crypto-hash` a dev dep
hwillson Aug 24, 2020
802a0ba
Ensure a `sha256` or `generateHash` function is provided
hwillson Aug 24, 2020
2f7abb5
Adjust tests to accommodate required sha256/generateHash options
hwillson Aug 24, 2020
349296c
Stop unnecessarily exporting `defaultOptions`
hwillson Aug 24, 2020
e4a32ef
Add link docs
hwillson Sep 10, 2020
3e3f5e7
Simplify createPersistedQueryLink options processing.
benjamn Sep 11, 2020
ce4d702
Allow GenerateHashFunction to return string | PromiseLike<string>.
benjamn Sep 11, 2020
68d3911
Use WeakMap to avoid adding Symbol properties to DocumentNode objects.
benjamn Sep 11, 2020
b333475
Simplify confusingly-named operationIsQuery helper.
benjamn Sep 11, 2020
8ad97aa
Support @apollo/client/link/persisted-queries in imports transform.
benjamn Sep 11, 2020
701eb3b
Mention PR #6837 in CHANGELOG.md.
benjamn Sep 11, 2020
f2b60c5
Merge pull request #6837 from apollographql/persisted-queries-link
benjamn Sep 11, 2020
62facae
Respect errorPolicy for mutation and subscription results. (#7003)
benjamn Sep 11, 2020
5441987
Bump @apollo/client npm version to 3.2.0-rc.0.
benjamn Sep 11, 2020
88afcd4
Merge branch 'main' into release-3.2.
benjamn Sep 14, 2020
9d3c847
Make CHANGELOG.md note about TypedDocumentNode more precise.
benjamn Sep 14, 2020
27304e2
Reorganize change list for v3.2.0.
benjamn Sep 14, 2020
b977779
Remove --tag beta from npm deploy command.
benjamn Sep 14, 2020
062b76b
Bump @apollo/client npm version to 3.2.0. :tada:
benjamn Sep 14, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,53 @@
## Apollo Client 3.2.0

## Bug Fixes

- Use `options.nextFetchPolicy` internally to restore original `FetchPolicy` after polling with `fetchPolicy: "network-only"`, so that polling does not interfere with normal query watching. <br/>
[@benjamn](https://github.com/benjamn) in [#6893](https://github.com/apollographql/apollo-client/pull/6893)

- Initialize `ObservableQuery` in `updateObservableQuery` even if `skip` is `true`. <br/>
[@mu29](https://github.com/mu29) in [#6999](https://github.com/apollographql/apollo-client/pull/6999)

- Prevent full reobservation of queries affected by optimistic mutation updates, while still delivering results from the cache. <br/>
[@benjamn](https://github.com/benjamn) in [#6854](https://github.com/apollographql/apollo-client/pull/6854)

## Improvements

- In TypeScript, all APIs that take `DocumentNode` parameters now may alternatively take `TypeDocumentNode<Data, Variables>`. This type has the same JavaScript representation but allows the APIs to infer the data and variable types instead of requiring you to specify types explicitly at the call site. <br/>
[@dotansimha](https://github.com/dotansimha) in [#6720](https://github.com/apollographql/apollo-client/pull/6720)

- Bring back an improved form of heuristic fragment matching, by allowing `possibleTypes` to specify subtype regular expression strings, which count as matches if the written result object has all the fields expected for the fragment. <br/>
[@benjamn](https://github.com/benjamn) in [#6901](https://github.com/apollographql/apollo-client/pull/6901)

- Allow `options.nextFetchPolicy` to be a function that takes the current `FetchPolicy` and returns a new (or the same) `FetchPolicy`, making `nextFetchPolicy` more suitable for global use in `defaultOptions.watchQuery`. <br/>
[@benjamn](https://github.com/benjamn) in [#6893](https://github.com/apollographql/apollo-client/pull/6893)

- Implement `useReactiveVar` hook for consuming reactive variables in React components. <br/>
[@benjamn](https://github.com/benjamn) in [#6867](https://github.com/apollographql/apollo-client/pull/6867)

- Move `apollo-link-persisted-queries` implementation to `@apollo/client/link/persisted-queries`. Try running our [automated imports transform](https://github.com/apollographql/apollo-client/tree/main/codemods/ac2-to-ac3) to handle this conversion, if you're using `apollo-link-persisted-queries`. <br/>
[@hwillson](https://github.com/hwillson) in [#6837](https://github.com/apollographql/apollo-client/pull/6837)

- Disable feud-stopping logic after any `cache.evict` or `cache.modify` operation. <br/>
[@benjamn](https://github.com/benjamn) in
[#6817](https://github.com/apollographql/apollo-client/pull/6817) and
[#6898](https://github.com/apollographql/apollo-client/pull/6898)

- Throw if `writeFragment` cannot identify `options.data` when no `options.id` provided. <br/>
[@jcreighton](https://github.com/jcreighton) in [#6859](https://github.com/apollographql/apollo-client/pull/6859)

- Provide `options.storage` object to `cache.modify` functions, as provided to `read` and `merge` functions. <br/>
[@benjamn](https://github.com/benjamn) in [#6991](https://github.com/apollographql/apollo-client/pull/6991)

- Allow `cache.modify` functions to return `details.INVALIDATE` (similar to `details.DELETE`) to invalidate the current field, causing affected queries to rerun, even if the field's value is unchanged. <br/>
[@benjamn](https://github.com/benjamn) in [#6991](https://github.com/apollographql/apollo-client/pull/6991)

- Support non-default `ErrorPolicy` values (that is, `"ignore"` and `"all"`, in addition to the default value `"none"`) for mutations and subscriptions, like we do for queries. <br/>
[@benjamn](https://github.com/benjamn) in [#7003](https://github.com/apollographql/apollo-client/pull/7003)

- Remove invariant forbidding a `FetchPolicy` of `cache-only` in `ObservableQuery#refetch`. <br/>
[@benjamn](https://github.com/benjamn) in [ccb0a79a](https://github.com/apollographql/apollo-client/pull/6774/commits/ccb0a79a588721f08bf87a131c31bf37fa3238e5), fixing [#6702](https://github.com/apollographql/apollo-client/issues/6702)

## Apollo Client 3.1.5

## Bug Fixes
Expand Down
4 changes: 4 additions & 0 deletions codemods/ac2-to-ac3/examples/link-packages.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { BatchLink } from 'apollo-link-batch';
import { BatchHttpLink } from 'apollo-link-batch-http';
import { setContext } from 'apollo-link-context';
import { ErrorLink } from 'apollo-link-error';
import {
VERSION,
createPersistedQueryLink,
} from 'apollo-link-persisted-queries';
import { RetryLink } from 'apollo-link-retry';
import { WebSocketLink } from 'apollo-link-ws';
// This package was unusual for having a default export.
Expand Down
1 change: 1 addition & 0 deletions codemods/ac2-to-ac3/imports.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default function transformer(file, api) {
'batch-http',
'context',
'error',
'persisted-queries',
'retry',
'schema',
'ws',
Expand Down
1 change: 1 addition & 0 deletions config/entryPoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const entryPoints = [
{ dirs: ['link', 'core'] },
{ dirs: ['link', 'error'] },
{ dirs: ['link', 'http'] },
{ dirs: ['link', 'persisted-queries'] },
{ dirs: ['link', 'retry'] },
{ dirs: ['link', 'schema'] },
{ dirs: ['link', 'utils'] },
Expand Down
3 changes: 2 additions & 1 deletion docs/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ module.exports = {
'api/link/apollo-link-rest',
'api/link/apollo-link-retry',
'api/link/apollo-link-schema',
'api/link/apollo-link-ws'
'api/link/apollo-link-ws',
'api/link/persisted-queries'
],
},
},
Expand Down
1 change: 1 addition & 0 deletions docs/source/api/cache/InMemoryCache.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ The first parameter of a modifier function is the current value of the field bei
| `canRead` | `CanReadFunction` | Returns `true` for non-normalized `StoreObjects` and non-dangling `Reference`s, indicating that `readField(name, objOrRef)` has a chance of working. Useful for filtering out dangling references from lists. |
| `isReference` | `boolean` | Utility to check if an object is a `{ __ref }` object. |
| `DELETE` | `any` | Sentinel object that can be returned from a modifier function to delete the field being modified. |
| `INVALIDATE` | `any` | Sentinel object that can be returned from a modifier function to invalidate the field, causing affected queries to rerun, without changing or deleting the field value. |

`Modifier` functions should return the value that is to be written into the cache for the field being modified, or a `DELETE` sentinel to remove the field.

Expand Down
164 changes: 164 additions & 0 deletions docs/source/api/link/persisted-queries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
---
title: Persisted Queries Link
description: Replace full queries with generated ID's to reduce bandwidth.
---

## Problem to solve

Unlike REST APIs that use a fixed URL to load data, GraphQL provides a rich query language that can be used to express the shape of application data requirements. This is a marvelous advancement in technology, but it comes at a cost: GraphQL query strings are often much longer than REST URLS — in some cases by many kilobytes.

In practice we've seen GraphQL query sizes ranging well above 10 KB *just for the query text*. This is significant overhead when compared with a simple URL of 50-100 characters. When paired with the fact that the uplink speed from the client is typically the most bandwidth-constrained part of the chain, large queries can become bottlenecks for client performance.

Automatic Persisted Queries solves this problem by sending a generated ID instead of the query text as the request.

For more information about this solution, read [this article announcing Automatic Persisted Queries](https://www.apollographql.com/blog/improve-graphql-performance-with-automatic-persisted-queries-c31d27b8e6ea/).

## How it works

1. When the client makes a query, it will optimistically send a short (64-byte) cryptographic hash instead of the full query text.
2. If the backend recognizes the hash, it will retrieve the full text of the query and execute it.
3. If the backend doesn't recognize the hash, it will ask the client to send the hash and the query text so it can store them mapped together for future lookups. During this request, the backend will also fulfill the data request.

This library is a client implementation for use with Apollo Client by using custom Apollo Link.

## Installation

This link is included in the `@apollo/client` package:

`npm install @apollo/client`

If you do not already have a SHA-256 based hashing function available in your application, you will need to install one separately. For example:

`npm install crypto-hash`

This link doesn't include a SHA-256 hash function by default, to avoid forcing one as a dependency. Developers should pick the most appropriate SHA-256 function (sync or async) for their needs/environment.

## Usage

The persisted query link requires using the `HttpLink`. The easiest way to use them together is to `concat` them into a single link.

```js
import { HttpLink, InMemoryCache, ApolloClient } from "@apollo/client";
import { createPersistedQueryLink } from "@apollo/client/link/persisted-queries";
import { sha256 } from 'crypto-hash';

const httpLink = new HttpLink({ uri: "/graphql" });
const persistedQueriesLink = createPersistedQueryLink({ sha256 });
const client = new ApolloClient({
cache: new InMemoryCache(),
link: persistedQueriesLink.concat(httpLink);
});
```

Thats it! Now your client will start sending query signatures instead of the full text resulting in improved network performance!

#### Options

The `createPersistedQueryLink` function takes a configuration object:

- `sha256`: a SHA-256 hashing function. Can be sync or async. Providing a SHA-256 hashing function is required, unless you're defining a fully custom hashing approach via `generateHash`.
- `generateHash`: an optional function that takes the query document and returns the hash. If provided this custom function will override the default hashing approach that uses the supplied `sha256` function. If not provided, the persisted queries link will use a fallback hashing approach leveraging the `sha256` function.
- `useGETForHashedQueries`: set to `true` to use the HTTP `GET` method when sending the hashed version of queries (but not for mutations). `GET` requests are not compatible with `@apollo/client/link/batch-http`.
> If you want to use `GET` for non-mutation queries whether or not they are hashed, pass `useGETForQueries: true` option to `HttpLink` instead. If you want to use `GET` for all requests, pass `fetchOptions: {method: 'GET'}` to `HttpLink`.
- `disable`: a function which takes an `ErrorResponse` (see below) and returns a boolean to disable any future persisted queries for that session. This defaults to disabling on `PersistedQueryNotSupported` or a 400 or 500 http error.

**ErrorResponse**

The argument that the optional `disable` function is given is an object with the following keys:

- `operation`: The Operation that encountered an error (contains `query`, `variables`, `operationName`, and `context`).
- `response`: The Execution of the response (contains `data` and `errors` as well `extensions` if sent from the server).
- `graphQLErrors`: An array of errors from the GraphQL endpoint.
- `networkError`: Any error during the link execution or server response.

*Note*: `networkError` is the value from the downlink's `error` callback. In most cases, `graphQLErrors` is the `errors` field of the result from the last `next` call. A `networkError` can contain additional fields, such as a GraphQL object in the case of a failing HTTP status code from `@apollo/link/http`. In this situation, `graphQLErrors` is an alias for `networkError.result.errors` if the property exists.

## Apollo Studio

Apollo Studio supports receiving and fulfilling Automatic Persisted Queries. Simply adding this link into your client app will improve your network response times when using Apollo Studio.

### Protocol

Automatic Persisted Queries are made up of three parts: the query signature, error responses, and the negotiation protocol.

**Query Signature**

The query signature for Automatic Persisted Queries is sent through the `extensions` field of a request from the client. This is a transport independent way to send extra information along with the operation.

```js
{
operationName: 'MyQuery',
variables: null,
extensions: {
persistedQuery: {
version: 1,
sha256Hash: hashOfQuery
}
}
}
```

When sending an Automatic Persisted Query, the client omits the `query` field normally present, and instead sends an extension field with a `persistedQuery` object as shown above. The hash algorithm defaults to a `sha256` hash of the query string.

If the client needs to register the hash, the query signature will be the same but include the full query text like so:

```js
{
operationName: 'MyQuery',
variables: null,
query: `query MyQuery { id }`,
extensions: {
persistedQuery: {
version: 1,
sha256Hash: hashOfQuery
}
}
}
```

This should only happen once across all clients when a new query is introduced into your application.

**Error Responses**

When the initial query signature is received by a backend, if it is unable to find the hash previously stored, it will send back the following response signature:

```js
{
errors: [
{ message: 'PersistedQueryNotFound' }
]
}
```

If the backend doesn't support Automatic Persisted Queries, or does not want to support it for that particular client, it can send back the following which will tell the client to stop trying to send hashes:

```
{
errors: [
{ message: 'PersistedQueryNotSupported' }
]
}
```

**Negotiation Protocol**

In order to support Automatic Persisted Queries, the client and server must follow the negotiation steps as outlined here:

*Happy Path*
1. Client sends query signature with no `query` field
2. Server looks up query based on hash, if found, it resolves the data
3. Client receives data and completes request

*Missing hash path*
1. Client sends query signature with no `query` field
2. Server looks up query based on hash, none is found
3. Server responds with NotFound error response
4. Client sends both hash and query string to Server
5. Server fulfills response and saves query string + hash for future lookup
6. Client receives data and completes request

### Build time generation

If you want to avoid hashing in the browser, you can use a build script to include the hash as part of the request, then pass a function to retrieve that hash when the operation is run. This works well with projects like [GraphQL Persisted Document Loader](https://github.com/leoasis/graphql-persisted-document-loader) which uses webpack to generate hashes at build time.

If you use the above loader, you can pass `{ generateHash: ({ documentId }) => documentId }` to the `createPersistedQueryLink` call.
30 changes: 30 additions & 0 deletions docs/source/caching/cache-interaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,36 @@ cache.modify({
});
```

### Example: Invalidating fields within a cached object

Normally, changing or deleting a field's value also _invalidates_ the field, causing watched queries to be reread if they previously consumed the field.

Using `cache.modify`, it's also possible to invalidate the field without changing or deleting its value, by returning the `INVALIDATE` sentinel:

```js
cache.modify({
id: cache.identify(myPost),
fields: {
comments(existingCommentRefs, { INVALIDATE }) {
return INVALIDATE;
},
},
});
```

If you need to invalidate all fields within the given object, you can pass a modifier function as the value of the `fields` option:

```js
cache.modify({
id: cache.identify(myPost),
fields(fieldValue, details) {
return details.INVALIDATE;
},
});
```

When using this form of `cache.modify`, you can determine the individual field names using `details.fieldName`. This technique works for any modifier function, not just those that return `INVALIDATE`.

## Obtaining an object's custom ID

If a type in your cache uses a [custom identifier](./cache-configuration/#customizing-identifier-generation-by-type) (or even if it doesn't), you can use the `cache.identify` method to obtain the identifier for an object of that type. This method takes an object and computes its ID based on both its `__typename` and its identifier field(s). This means you don't have to keep track of which fields make up each type's identifier.
Expand Down
34 changes: 28 additions & 6 deletions docs/source/local-state/managing-state-with-field-policies.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,14 @@ This `read` function returns the value of our reactive variable whenever `cartIt

Now, let's create a button component that enables the user to add a product to their cart:

```jsx{8}:title=AddToCartButton.js
```jsx{7}:title=AddToCartButton.js
import { cartItemsVar } from './cache';
// ... other imports

export function AddToCartButton({ productId }) {
const cartItems = cartItemsVar();
return (
<div class="add-to-cart-button">
<Button onClick={() => cartItemsVar([...cartItems, productId])}>
<Button onClick={() => cartItemsVar([...cartItemsVar(), productId])}>
Add to Cart
</Button>
</div>
Expand All @@ -167,8 +166,6 @@ On click, this button updates the value of `cartItemsVar` to append the button's

Here's a `Cart` component that uses the `GET_CART_ITEMS` query and therefore refreshes automatically whenever the value of `cartItemsVar` changes:

<ExpansionPanel title="Expand example">

```jsx:title=Cart.js
export const GET_CART_ITEMS = gql`
query GetCartItems {
Expand Down Expand Up @@ -199,7 +196,32 @@ export function Cart() {
}
```

</ExpansionPanel>
Alternatively, you can read directly from a reactive variable using the `useReactiveVar` hook introduced in Apollo Client 3.2.0:

```jsx:title=Cart.js
import { useReactiveVar } from '@apollo/client';

export function Cart() {
const cartItems = useReactiveVar(cartItemsVar);

return (
<div class="cart">
<Header>My Cart</Header>
{cartItems.length === 0 ? (
<p>No items in your cart</p>
) : (
<Fragment>
{cartItems.map(productId => (
<CartItem key={productId} />
))}
</Fragment>
)}
</div>
);
}
```

As in the earlier `useQuery` example, whenever the `cartItemsVar` variable is updated, any currently-mounted `Cart` components will rerender. Calling `cartItemsVar()` without `useReactiveVar` will not capture this dependency, so future variable updates will not rerender the component. Both of these approaches are useful in different situations.

### Storing local state in the cache

Expand Down
Loading