Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.

(docs) - Apply edits to automatically flagged errors (#1437)

authored by kitten.sh and committed by

GitHub ac199a70 530e2312

+231 -215
+1 -1
docs/README.md
··· 7 7 8 8 `urql` is a highly customizable and versatile GraphQL client with which you add on features like 9 9 normalized caching as you grow. It's built to be both easy to use for newcomers to 10 - GraphQL, as well as extensible, to grow to support dynamic single-app applications and highly 10 + GraphQL, and extensible, to grow to support dynamic single-app applications and highly 11 11 customized GraphQL infrastructure. In short, `urql` prioritizes usability and adaptability. 12 12 13 13 As you're adopting GraphQL, `urql` becomes your primary data layer and can handle content-heavy
+2 -2
docs/advanced/README.md
··· 21 21 - [**Authentication**](./authentication.md) describes how to implement authentication using the `authExchange` 22 22 - [**Testing**](./testing.md) covers how to test components that use `urql` particularly in React. 23 23 - [**Authoring Exchanges**](./authoring-exchanges.md) describes how to implement exchanges from 24 - scratch and how they work internally. This is a good basis to understanding how some of the 24 + scratch and how they work internally. This is a good basis to understanding how some 25 25 features in this section function. 26 - - [**Auto-populate Mutations**](./auto-populate-mutations.md) presents the `populateExchange` addon which can make it easier to 26 + - [**Auto-populate Mutations**](./auto-populate-mutations.md) presents the `populateExchange` addon, which can make it easier to 27 27 update normalized data after mutations.
+35 -24
docs/advanced/authentication.md
··· 12 12 13 13 ## Typical Authentication Flow 14 14 15 - **Initial login** - the user opens the application and authenticates for the first time. They enter their credentials and receive an auth token. 15 + **Initial login** — the user opens the application and authenticates for the first time. They enter their credentials and receive an auth token. 16 16 The token is saved to storage that is persisted though sessions, e.g. `localStorage` on the web or `AsyncStorage` in React Native. The token is 17 17 added to each subsequent request in an auth header. 18 18 19 - **Resume** - the user opens the application after having authenticated in the past. In this case, we should already have the token in persisted 19 + **Resume** — the user opens the application after having authenticated in the past. In this case, we should already have the token in persisted 20 20 storage. We fetch the token from storage and add to each request, usually as an auth header. 21 21 22 - **Forced log out due to invalid token** - the user's session could become invalid for a variety reasons: their token expired, they requested to be 23 - signed out of all devices, or their session was invalidated remotely. In this case, we would want to also log them out in the application so they 22 + **Forced log out due to invalid token** — the user's session could become invalid for a variety reasons: their token expired, they requested to be 23 + signed out of all devices, or their session was invalidated remotely. In this case, we would want to 24 + also log them out in the application, so they 24 25 could have the opportunity to log in again. To do this, we want to clear any persisted storage, and redirect them to the application home or login page. 25 26 26 - **User initiated log out** - when the user chooses to log out of the application, we usually send a logout request to the API, then clear any tokens 27 + **User initiated log out** — when the user chooses to log out of the application, we usually send a logout request to the API, then clear any tokens 27 28 from persisted storage, and redirect them to the application home or login page. 28 29 29 - **Refresh (optional)** - this is not always implemented, but given that your API supports it, the user will receive both an auth token and a refresh token, 30 - where the auth token is valid for a shorter duration of time (e.g. 1 week) than the refresh token (e.g. 6 months) and the latter can be used to request a new 30 + **Refresh (optional)** — this is not always implemented; if your API supports it, the 31 + user will receive both an auth token, and a refresh token. 32 + The auth token is usually valid for a shorter duration of time (e.g. 1 week) than the refresh token 33 + (e.g. 6 months), and the latter can be used to request a new 31 34 auth token if the auth token has expired. The refresh logic is triggered either when the JWT is known to be invalid (e.g. by decoding it and inspecting the expiry date), 32 35 or when an API request returns with an unauthorized response. For graphQL APIs, it is usually an error code, instead of a 401 HTTP response, but both can be supported. 33 36 When the token as been successfully refreshed (this can be done as a mutation to the graphQL API or a request to a different API endpoint, depending on implementation), ··· 86 89 ``` 87 90 88 91 We check that the `authState` doesn't already exist (this indicates that it is the first time this exchange is executed and not an auth failure) and fetch the auth state from 89 - storage. The structure of this particular`authState` is an object with keys for `token` and `refreshToken`, but this format is not required. You can 90 - use different keys or store any additional auth related information here. For example you could decode and store the token expiry date, which would save you from decoding 91 - your JWT every time you want to check whether your token is expired. 92 + storage. The structure of this particular `authState` is an object with keys for `token` and 93 + `refreshToken`, but this format is not required. We can use different keys or store any additional 94 + auth related information here. For example, we could decode and store the token expiry date, which 95 + would save us from decoding the JWT every time we want to check whether it has expired. 92 96 93 97 In React Native, this is very similar, but because persisted storage in React Native is always asynchronous, so is this function: 94 98 ··· 109 113 110 114 ### Configuring `addAuthToOperation` 111 115 112 - The purpose of `addAuthToOperation` is to take apply your auth state to each request. Note that the format of the `authState` will be whatever 113 - you've returned from `getAuth` and not at all constrained by the exchange: 116 + The purpose of `addAuthToOperation` is to apply an auth state to each request. Note that the format 117 + of the `authState` will be whatever we've returned from `getAuth` and not constrained by the exchange: 114 118 115 119 ```js 116 120 import { makeOperation } from '@urql/core'; ··· 138 142 }; 139 143 ``` 140 144 141 - First we check that we have an `authState` and a `token`. Then we apply it to the request `fetchOptions` as an `Authorization` header. 142 - The header format can vary based on the API (e.g using `Bearer ${token}` instead of just `token`) which is why it'll be up to you to add the header 143 - in the expected format for your API. 145 + First, we check that we have an `authState` and a `token`. Then we apply it to the request 146 + `fetchOptions` as an `Authorization` header. The header format can vary based on the API (e.g. using 147 + `Bearer ${token}` instead of just `token`) which is why it'll be up to us to add the header 148 + in the expected format for our API. 144 149 145 150 ### Configuring `didAuthError` 146 151 147 152 This function lets the exchange know what is defined to be an API error for your API. `didAuthError` receives an `error` which is of type 148 - [`CombinedError`](../api/core.md#combinederror) and we can use the `graphQLErrors` array in `CombinedError` to determine if an auth error has occurred. 153 + [`CombinedError`](../api/core.md#combinederror), and we can use the `graphQLErrors` array in `CombinedError` to determine if an auth error has occurred. 149 154 150 155 The GraphQL error looks like something like this: 151 156 ··· 165 170 } 166 171 ``` 167 172 168 - Most GraphQL APIs will communicate auth errors via the [error code extension](https://www.apollographql.com/docs/apollo-server/data/errors/#codes) which 169 - is the recommended approach. We'll be able to determine whether any of the GraphQL errors were due to an unauthorized error code, which would indicate an auth failure: 173 + Most GraphQL APIs will communicate auth errors via the [error code 174 + extension](https://www.apollographql.com/docs/apollo-server/data/errors/#codes), which 175 + is the recommended approach. We'll be able to determine whether any of the GraphQL errors were due 176 + to an unauthorized error code, which would indicate an auth failure: 170 177 171 178 ```js 172 179 const didAuthError = ({ error }) => { ··· 203 210 204 211 ### Configuring `getAuth` (triggered after an auth error has occurred) 205 212 206 - If your API doesn't support any sort of token refresh, this is where you should simply log the user out. 213 + If the API doesn't support any sort of token refresh, this is where we could simply log the user out. 207 214 208 215 ```js 209 216 const getAuth = async ({ authState }) => { ··· 222 229 }; 223 230 ``` 224 231 225 - Here, `logout()` is a placeholder that is called when we got an error, so that we can redirect to a login page again and clear our tokens from local storage or otherwise. 232 + Here, `logout()` is a placeholder that is called when we got an error, so that we can redirect to a 233 + login page again and clear our tokens from local storage or otherwise. 226 234 227 - If we had a way to refresh our token using a refresh token, we can attempt to get a new token for the user first: 235 + If we had a way to refresh our token using a refresh token, we can attempt to get a new token for the 236 + user first: 228 237 229 238 ```js 230 239 const getAuth = async ({ authState, mutate }) => { ··· 342 351 When the application launches, the first thing we do is check whether the user has any auth tokens in persisted storage. This will tell us 343 352 whether to show the user the logged in or logged out view. 344 353 345 - The `isLoggedIn` prop should always be updated based on authentication state change e.g. set to `true` after the use has authenticated and their tokens have been 346 - added to storage, and set to `false` if the user has been logged out and their tokens have been cleared. It's important clear or add tokens to storage _before_ 347 - updating the prop in order for the auth exchange to work correctly. 354 + The `isLoggedIn` prop should always be updated based on authentication state change. For instance, we may set it to 355 + `true` after the user has authenticated and their tokens have been added to storage, and set it to 356 + `false` once the user has been logged out and their tokens have been cleared. It's important to clear 357 + or add tokens to a storage _before_ updating the prop in order for the auth exchange to work 358 + correctly.
+8 -7
docs/advanced/authoring-exchanges.md
··· 55 55 56 56 **Second,** operations are checked against the cache. Depending on the `requestPolicy`, 57 57 cached results can be resolved from here instead, which would mean that the cache sends back the 58 - result and the operation doesn't travel any further in the chain. 58 + result, and the operation doesn't travel any further in the chain. 59 59 60 - **Third,** operations are sent to the API and the result is turned into an `OperationResult`. 60 + **Third,** operations are sent to the API, and the result is turned into an `OperationResult`. 61 61 62 62 **Lastly,** operation results then travel through the exchanges in _reverse order_, which is because 63 63 exchanges are a pipeline where all operations travel forward deeper into the exchange chain, and ··· 118 118 ``` 119 119 120 120 This exchange does nothing else than forward all operations and return all results. Hence, it's 121 - called a `noopExchange` - an exchange that doesn't do anything. 121 + called a `noopExchange` — an exchange that doesn't do anything. 122 122 123 123 ### Forward and Return Composition 124 124 ··· 155 155 ### Only One Operations Stream 156 156 157 157 When writing an Exchange we have to be careful not to _split_ the stream into multiple ones by 158 - subscribing multiple times. Streams are lazy and immutable by default. Every time you use them, a new chain of streaming operators is created; since Exchanges are technically side-effects, we don't want to 159 - accidentally have multiple instances of them in parallel. 158 + subscribing multiple times. Streams are lazy and immutable by default. Every time you use them, 159 + a new chain of streaming operators is created; since Exchanges are technically side effects, we don't 160 + want to accidentally have multiple instances of them in parallel. 160 161 161 162 The `ExchangeIO` function receives an `operations$` stream. It's important to be careful to either only 162 163 use it once, or to _share_ its subscription. ··· 289 290 synchronous. The `fetchExchange` is asynchronous since 290 291 it makes a `fetch` request and waits for a server response. 291 292 292 - When you're adding more exchanges it's often crucial 293 - to put them in a specific order. For instance - an authentication exchange 293 + When you're adding more exchanges, it's often crucial 294 + to put them in a specific order. For instance, an authentication exchange 294 295 will need to go before the `fetchExchange`, a secondary cache will probably have to 295 296 go in front of the default cache exchange. 296 297
+5 -5
docs/advanced/auto-populate-mutations.md
··· 7 7 8 8 The `populateExchange` allows you to auto-populate selection sets in your mutations using the 9 9 `@populate` directive. In combination with [Graphcache](../graphcache/README.md) this is a useful 10 - tool to update the data in your application automatically following a mutation, when your app grows 10 + tool to update the data in your application automatically following a mutation, when your app grows, 11 11 and it becomes harder to track all fields that have been queried before. 12 12 13 - > **NOTE:** The `populateExchange` is currently _experimental_! Certain patterns and usage paths 13 + > **NOTE:** The `populateExchange` is _experimental_! Certain patterns and usage paths 14 14 > like GraphQL field arguments aren't covered yet, and the exchange hasn't been extensively used 15 15 > yet. 16 16 ··· 48 48 49 49 ## Example usage 50 50 51 - Consider the following queries which have been requested in other parts of your application: 51 + Consider the following queries, which have been requested in other parts of your application: 52 52 53 53 ```graphql 54 54 # Query 1 ··· 92 92 93 93 ### Choosing when to populate 94 94 95 - You may not want to populate your whole mutation response. In order to reduce your payload, pass populate lower in your query. 95 + You may not want to populate your whole mutation response. To reduce your payload, pass populate lower in your query. 96 96 97 97 ```graphql 98 98 mutation addTodo(id: ID!) { ··· 106 106 ### Using aliases 107 107 108 108 If you find yourself using multiple queries with variables, it may be necessary to 109 - [use aliases](https://graphql.org/learn/queries/#aliases) in order to allow merging of queries. 109 + [use aliases](https://graphql.org/learn/queries/#aliases) to allow merging of queries. 110 110 111 111 > **Note:** This caveat may change in the future or this restriction may be lifted. 112 112
+3 -3
docs/advanced/debugging.md
··· 10 10 11 11 ## Devtools 12 12 13 - The quickest way to debug `urql` is to use the [`urql` devtools.](https://github.com/FormidableLabs/urql-devtools/) 13 + It's easiest to debug `urql` with the [`urql` devtools.](https://github.com/FormidableLabs/urql-devtools/) 14 14 15 15 It offers tools to inspect internal ["Debug Events"](#debug-events) as they happen, to explore data 16 16 as your app is seeing it, and to quickly trigger GraphQL queries. ··· 125 125 126 126 ### Tips 127 127 128 - Lastly, in summary, here are a few tips, dos, and don'ts that are important when we're adding new 129 - Debug Events to custom exchanges. 128 + Lastly, in summary, here are a few tips, that are important when we're adding new Debug Events to 129 + custom exchanges: 130 130 131 131 - ✅ **Share internal details**: Frequent debug messages on key events inside your exchange are very 132 132 useful when later inspecting them, e.g. in the `devtools`.
+3 -3
docs/advanced/persistence-and-uploads.md
··· 22 22 hash and sends this hash instead of the full query. If the server has seen this GraphQL query before 23 23 it will recognise it by its hash and process the GraphQL API request as usual, otherwise it may 24 24 respond using a `PersistedQueryNotFound` error. In that case the client is supposed to instead send 25 - the full GraphQL query and the hash together, which will cause the query to be "registered" with the 25 + the full GraphQL query, and the hash together, which will cause the query to be "registered" with the 26 26 server. 27 27 28 28 Additionally we could also decide to send these hashed queries as GET requests instead of POST ··· 76 76 ### Customizing Hashing 77 77 78 78 The `persistedFetchExchange` also accepts a `generateHash` option. This may be used to swap out the 79 - exchange's default method of generating SHA256 hashes. By default the exchange will use the 79 + exchange's default method of generating SHA256 hashes. By default, the exchange will use the 80 80 built-in [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) on the 81 81 browser, which has been implemented to support IE11 as well. In Node.js it'll use the [Node 82 82 Crypto Module](https://nodejs.org/api/crypto.html) instead. ··· 158 158 ``` 159 159 160 160 If you're using the `persistedFetchExchange` then put the `persistedFetchExchange` in front of the 161 - `multipartFetchExchange`, since only the latter is a full replacement for the `fetchExchange` and 161 + `multipartFetchExchange`, since only the latter is a full replacement for the `fetchExchange`, and 162 162 the former only handled query operations. 163 163 164 164 [Read more about `@urql/multipart-fetch-exchange` in our API
+2 -2
docs/advanced/retry-operations.md
··· 6 6 # Retrying Operations 7 7 8 8 The `retryExchange` lets us retry specific operation, by default it will 9 - retry only network errors but we can specify additional options to add 9 + retry only network errors, but we can specify additional options to add 10 10 functionality. 11 11 12 12 ## Installation and Setup ··· 55 55 56 56 We have the `initialDelayMs` to specify at what interval the `retrying` should start, this means that if we specify `1000` that when our `operation` fails we'll wait 1 second and then retry it. 57 57 58 - Next up is the `maxDelayMs`, our `retryExchange` will keep increasing the time between retries so we don't spam our server with requests it can't complete, this option ensures we don't exceed a certain threshold. This time between requests will increase with a random `back-off` factor multiplied by the `initialDelayMs`, read more about the [thundering herd problem](https://en.wikipedia.org/wiki/Thundering_herd_problem). 58 + Next up is the `maxDelayMs`, our `retryExchange` will keep increasing the time between retries, so we don't spam our server with requests it can't complete, this option ensures we don't exceed a certain threshold. This time between requests will increase with a random `back-off` factor multiplied by the `initialDelayMs`, read more about the [thundering herd problem](https://en.wikipedia.org/wiki/Thundering_herd_problem). 59 59 60 60 Talking about increasing the `delay` randomly, `randomDelay` allows us to disable this. When this option is set to `false` we'll only increase the time between attempts with the `initialDelayMs`. This means if we fail the first time we'll have 1 second wait, next fail we'll have 2 seconds and so on. 61 61
+8 -8
docs/advanced/server-side-rendering.md
··· 64 64 `; 65 65 ``` 66 66 67 - This will provide `__URQL_DATA__` globally which we've used in our first example to inject data into 67 + This will provide `__URQL_DATA__` globally, which we've used in our first example to inject data into 68 68 the `ssrExchange` on the client-side. 69 69 70 70 Alternatively you can also call `restoreData` as long as this call happens synchronously before the ··· 86 86 or `renderToNodeStream`](https://reactjs.org/docs/react-dom-server.html#rendertostring). 87 87 88 88 For React, `urql` has a "Suspense mode" that [allows data fetching to interrupt 89 - rendering](https://reactjs.org/docs/concurrent-mode-suspense.html). However, suspense is currently 89 + rendering](https://reactjs.org/docs/concurrent-mode-suspense.html). However, Suspense is 90 90 not supported by React during server-side rendering. 91 91 92 92 Using [the `react-ssr-prepass` package](https://github.com/FormidableLabs/react-ssr-prepass) however, ··· 158 158 ### With Preact 159 159 160 160 If you're using Preact instead of React, there's a drop-in replacement package for 161 - `react-ssr-prepass`, which is called `preact-ssr-prepass`. It only has a peer dependency on Preact 161 + `react-ssr-prepass`, which is called `preact-ssr-prepass`. It only has a peer dependency on Preact, 162 162 and we can install it like so: 163 163 164 164 ```sh ··· 167 167 npm install --save preact-ssr-prepass preact 168 168 ``` 169 169 170 - All above examples for `react-ssr-prepass` will still be the exact same, except that instead of 170 + All above examples for `react-ssr-prepass` will still be the same, except that instead of 171 171 using the `urql` package we'll have to import from `@urql/preact`, and instead of `react-ssr-prepass` 172 172 we'll have to import from. `preact-ssr-prepass`. 173 173 ··· 181 181 this integration contains convenience methods specifically for `Next.js`. 182 182 These will simplify the above setup for SSR. 183 183 184 - To setup `next-urql`, first we'll install `next-urql` with `react-is` and `urql` as 184 + To set up `next-urql`, first we'll install `next-urql` with `react-is` and `urql` as 185 185 peer dependencies: 186 186 187 187 ```sh ··· 222 222 223 223 This will automatically set up server-side rendering on the page. The `withUrqlClient` higher-order 224 224 component function accepts the usual `Client` options as an argument. This may either just be an 225 - object or a function that receives the Next.js' `getInitialProps` context. 225 + object, or a function that receives the Next.js' `getInitialProps` context. 226 226 227 227 One added caveat is that these options may not include the `exchanges` option because `next-urql` 228 228 injects the `ssrExchange` automatically at the right location. If you're setting up custom exchanges ··· 306 306 307 307 ### Resetting the client instance 308 308 309 - In rare scenario's you possibly will have to reset the client instance (reset all cache, ...), this is an uncommon scenario 310 - and we consider it "unsafe" so evaluate this carefully for yourself. 309 + In rare scenario's you possibly will have to reset the client instance (reset all cache, ...), this 310 + is an uncommon scenario, and we consider it "unsafe" so evaluate this carefully for yourself. 311 311 312 312 When this does seem like the appropriate solution any component wrapped with `withUrqlClient` will receive the `resetUrqlClient` 313 313 property, when invoked this will create a new top-level client and reset all prior operations.
+5 -2
docs/advanced/subscriptions.md
··· 33 33 In the above example, we add the `subscriptionExchange` to the `Client` with the default exchanges 34 34 add before it. The `subscriptionExchange` is a factory that accepts additional options and returns 35 35 the actual `Exchange` function. It does not make any assumption over the transport protocol and 36 - scheme that is used. Instead, we need to pass a `forwardSubscription` function which is called with 36 + scheme that is used. Instead, we need to pass a `forwardSubscription` function, which is called with 37 37 an "enriched" _Operation_ every time the `Client` attempts to execute a GraphQL Subscription. 38 38 39 39 When we define this function it must return an "Observable-like" object, which needs to follow the ··· 304 304 `Client`'s `subscription` method for one-off subscriptions. This method is similar to the ones for 305 305 mutations and subscriptions [that we've seen before on the "Core Package" page.](../basics/core.md) 306 306 307 - This method will always [returns a Wonka stream](../architecture.md#the-wonka-library) and doesn't have a `.toPromise()` shortcut method, since promises won't return the multiple values that a subscription may deliver. Let's convert the above example to one without framework code, as we may use subscriptions in a Node.js environment. 307 + This method will always [returns a Wonka stream](../architecture.md#the-wonka-library) and doesn't 308 + have a `.toPromise()` shortcut method, since promises won't return the multiple values that a 309 + subscription may deliver. Let's convert the above example to one without framework code, as we may 310 + use subscriptions in a Node.js environment. 308 311 309 312 ```js 310 313 import { pipe, subscribe } from 'wonka';
+7 -7
docs/advanced/testing.md
··· 23 23 24 24 In the section ["Stream Patterns" on the "Architecture" page](../architecture.md) we've seen, that 25 25 all methods on the client operate with and return streams. These streams are created using 26 - [the Wonka library](../architecture.md#the-wonka-library) and we're able to create streams 26 + [the Wonka library](../architecture.md#the-wonka-library), and we're able to create streams 27 27 ourselves to mock the different states of our operations, e.g. fetching, errors, or success with data. 28 28 29 29 You'll probably use one of these utility functions to create streams: ··· 98 98 99 99 ### Fetching 100 100 101 - Fetching states can be simulated by returning a stream which never returns. Wonka provides a utility for this, aptly called `never`. 101 + Fetching states can be simulated by returning a stream, which never returns. Wonka provides a utility for this, aptly called `never`. 102 102 103 - Here's a fixture which stays in the _fetching_ state. 103 + Here's a fixture, which stays in the _fetching_ state. 104 104 105 105 ```tsx 106 106 import { Provider } from 'urql'; ··· 120 120 121 121 ### Response (success) 122 122 123 - Response states are simulated by providing a stream which contains a network response. For single responses, Wonka's `fromValue` function can do this for us. 123 + Response states are simulated by providing a stream, which contains a network response. For single responses, Wonka's `fromValue` function can do this for us. 124 124 125 125 **Example snapshot test of response state** 126 126 ··· 185 185 }); 186 186 ``` 187 187 188 - The above client we've created mocks all three operations — queries, mutations, and subscriptions — to always remain in the `fetching: true` state. 188 + The above client we've created mocks all three operations — queries, mutations and subscriptions — to always remain in the `fetching: true` state. 189 189 Generally when we're _hoisting_ our mocked client and reuse it across multiple tests we have to be 190 190 mindful not to instantiate the mocks outside of Jest's lifecycle functions (like `it`, `beforeEach`, 191 191 `beforeAll` and such) as it may otherwise reset our mocked functions' return values or ··· 197 197 198 198 If you prefer to have more control on when the new data is arriving you can use the `makeSubject` utility from Wonka. You can see more details in the next section. 199 199 200 - Here's an example of testing a list component which uses a subscription. 200 + Here's an example of testing a list component, which uses a subscription. 201 201 202 202 ```tsx 203 203 import { OperationContext, makeOperation } from '@urql/core'; ··· 236 236 237 237 Simulating multiple responses can be useful, particularly testing `useEffect` calls dependent on changing query responses. 238 238 239 - For this, a _subject_ is the way to go. In short, it's a stream which you can push responses to. The `makeSubject` function from Wonka is what you'll want to use for this purpose. 239 + For this, a _subject_ is the way to go. In short, it's a stream that you can push responses to. The `makeSubject` function from Wonka is what you'll want to use for this purpose. 240 240 241 241 Below is an example of simulating subsequent responses (such as a cache update/refetch) in a test. 242 242
+9 -9
docs/api/core.md
··· 5 5 6 6 # @urql/core 7 7 8 - The `@urql/core` package is the basis of all framework bindings. Every bindings package, 9 - like [`urql` for React](./urql.md) or [`@urql/preact`](./preact.md) will reuse the core logic and 8 + The `@urql/core` package is the basis of all framework bindings. Each bindings-package, 9 + like [`urql` for React](./urql.md) or [`@urql/preact`](./preact.md), will reuse the core logic and 10 10 reexport all exports from `@urql/core`. 11 11 Therefore if you're not accessing utilities directly, aren't in a Node.js environment, and are using 12 12 framework bindings, you'll likely want to import from your framework bindings package directly. ··· 27 27 | `fetchOptions` | `RequestInit \| () => RequestInit` | Additional `fetchOptions` that `fetch` in `fetchExchange` should use to make a request | 28 28 | `fetch` | `typeof fetch` | An alternative implementation of `fetch` that will be used by the `fetchExchange` instead of `window.fetch` | 29 29 | `suspense` | `?boolean` | Activates the experimental React suspense mode, which can be used during server-side rendering to prefetch data | 30 - | `requestPolicy` | `?RequestPolicy` | Changes the default request policy that will be used. By default this will be `cache-first`. | 30 + | `requestPolicy` | `?RequestPolicy` | Changes the default request policy that will be used. By default, this will be `cache-first`. | 31 31 | `preferGetMethod` | `?boolean` | This is picked up by the `fetchExchange` and will force all queries (not mutations) to be sent using the HTTP GET method instead of POST. | 32 32 | `maskTypename` | `?boolean` | Enables the `Client` to automatically apply the `maskTypename` utility to all `data` on [`OperationResult`s](#operationresult). This makes the `__typename` properties non-enumerable. | 33 33 ··· 62 62 This is a shorthand method for [`client.executeQuery`](#clientexecutequery), which accepts a query 63 63 (`DocumentNode | string`) and variables separately and creates a [`GraphQLRequest`](#graphqlrequest) [`createRequest`](#createrequest) automatically. 64 64 65 - The returned `Source<OperationResult>` will also have an added `toPromise` method so the stream can 65 + The returned `Source<OperationResult>` will also have an added `toPromise` method, so the stream can 66 66 be conveniently converted to a promise. 67 67 68 68 ```js ··· 286 286 `true` or `false` to tell the `ssrExchange` whether to 287 287 write to (server-side) or read from (client-side) the cache. 288 288 289 - By default `isClient` defaults to `true` when the `Client.suspense` 289 + By default, `isClient` defaults to `true` when the `Client.suspense` 290 290 mode is disabled and to `false` when the `Client.suspense` mode 291 291 is enabled. 292 292 ··· 307 307 during the server-side rendering pass, and allows you to populate 308 308 the cache on the client-side with the same data. 309 309 310 - During React rehydration this cache will be emptied and it will 310 + During React rehydration this cache will be emptied, and it will 311 311 become inactive and won't change the results of queries after 312 312 rehydration. 313 313 ··· 409 409 ### makeOperation 410 410 411 411 This utility is used to either turn a [`GraphQLRequest` object](#graphqlrequest) into a new 412 - [`Operation` object](#operation) or to copy an `Operation`. It adds the `kind` property and the 412 + [`Operation` object](#operation) or to copy an `Operation`. It adds the `kind` property, and the 413 413 `operationName` alias that outputs a deprecation warning. 414 414 415 415 It accepts three arguments: ··· 463 463 and marks every `__typename` property as non-enumerable. 464 464 465 465 The [`formatDocument`](#formatdocument) is often used by `urql` automatically and adds `__typename` 466 - fields to all results. However, this means that data can often not be passed back into variables or 467 - inputs on mutations, which is a common use-case. This utility hides these fields which can solves 466 + fields to all results. However, this means that data often cannot be passed back into variables or 467 + inputs on mutations, which is a common use-case. This utility hides these fields, which can solve 468 468 this problem. 469 469 470 470 It's used by the [`Client`](#client) when the `maskTypename` option is enabled.
+6 -6
docs/api/urql.md
··· 20 20 This hook returns a tuple of the shape `[result, executeQuery]`. 21 21 22 22 - The `result` is an object with the shape of an [`OperationResult`](./core.md#operationresult) with 23 - an added `fetching: boolean` property, indicating whether the query is currently being fetched. 23 + an added `fetching: boolean` property, indicating whether the query is being fetched. 24 24 - The `executeQuery` function optionally accepts 25 25 [`Partial<OperationContext>`](./core.md#operationcontext) and reexecutes the current query when 26 26 it's called. When `pause` is set to `true` this executes the query, overriding the otherwise ··· 34 34 `[result, executeMutation]`. 35 35 36 36 - The `result` is an object with the shape of an [`OperationResult`](./core.md#operationresult) with 37 - an added `fetching: boolean` property, indicating whether the mutation is currently being executed. 37 + an added `fetching: boolean` property, indicating whether the mutation is being executed. 38 38 - The `executeMutation` function accepts variables and optionally 39 39 [`Partial<OperationContext>`](./core.md#operationcontext) and may be used to start executing a 40 40 mutation. It returns a `Promise` resolving to an [`OperationResult`](./core.md#operationresult). ··· 73 73 it's called. When `pause` is set to `true` this starts the subscription, overriding the otherwise 74 74 paused hook. 75 75 76 - Since a subscription may proactively closed by the server, the additional `fetching: boolean` 77 - property on the `result` may update to `false` when the server ends the subscription. 78 - By default `urql` is not able to start subscriptions, since this requires some additional setup. 76 + The `fetching: boolean` property on the `result` may change to `false` when the server proactively 77 + ends the subscription. By default, `urql` is unable able to start subscriptions, since this requires 78 + some additional setup. 79 79 80 80 [Read more about how to use the `useSubscription` API on the "Subscriptions" 81 81 page.](../advanced/subscriptions.md) ··· 97 97 This component is a wrapper around [`useMutation`](#usemutation), exposing a [render prop 98 98 API](https://reactjs.org/docs/render-props.html) for cases where hooks aren't desirable. 99 99 100 - The `Mutation` component accepts a `query` prop and a function callback must be passed to `children` 100 + The `Mutation` component accepts a `query` prop, and a function callback must be passed to `children` 101 101 that receives the mutation result and must return a React element. The second argument of 102 102 `useMutation`'s returned tuple, `executeMutation` is passed as an added property on the mutation 103 103 result object.
+10 -10
docs/architecture.md
··· 35 35 36 36 If `urql` was a train it would take several stops to arrive at its terminus, our API. It starts with us 37 37 defining queries or mutations. Any GraphQL request can be abstracted into their query documents and 38 - their variables. In `urql`, these GraphQL requests are treated as unique objects which are uniquely 38 + their variables. In `urql`, these GraphQL requests are treated as unique objects, which are uniquely 39 39 identified by the query document and variables (which is why a `key` is generated from the two). This 40 40 `key` is a hash number of the query document and variables and uniquely identifies our 41 41 [`GraphQLRequest`](./api/core.md#graphqlrequest). ··· 66 66 ![Operations and Results](./assets/urql-event-hub.png) 67 67 68 68 It's the `Client`s responsibility to accept an `Operation` and execute it. The bindings interally 69 - call the `client.executeQuery`, `client.executeMutation`, or `client.executeSubscription` methods 69 + call the `client.executeQuery`, `client.executeMutation`, or `client.executeSubscription` methods, 70 70 and we'll get a "stream" of results. This "stream" allows us to register a callback with it to 71 71 receive results. 72 72 73 73 In the diagram we can see that each operation is a signal for our request to start at which point 74 74 we can expect to receive our results eventually on a callback. Once we're not interested in results 75 75 anymore a special "teardown" signal is issued on the `Client`. While we don't see operations outside 76 - of the `Client`, they're what travel through the "Exchanges" on the `Client`. 76 + the `Client`, they're what travel through the "Exchanges" on the `Client`. 77 77 78 78 ## The Client and Exchanges 79 79 80 80 To reiterate, when we use `urql`'s bindings for our framework of choice, methods are called on the 81 - `Client` but we never see the operations that are created in the background from our bindings. We 81 + `Client`, but we never see the operations that are created in the background from our bindings. We 82 82 call a method like `client.executeQuery` (or it's called for us in the bindings), an operation is 83 83 issued internally when we subscribe with a callback, and later our callback is called with results. 84 84 ··· 95 95 our perspective: 96 96 97 97 - We subscribe to a "stream" and expect to get results on a callback 98 - - The `Client` issues the operation and we'll receive some results back eventually as either the 99 - cache responds (synchronously) or the request gets sent to our API. 100 - - We eventually unsubscribe and the `Client` issues a "teardown" operation with the same `key` as 98 + - The `Client` issues the operation, and we'll receive some results back eventually as either the 99 + cache responds (synchronously), or the request gets sent to our API. 100 + - We eventually unsubscribe, and the `Client` issues a "teardown" operation with the same `key` as 101 101 the original operation, which concludes our flow. 102 102 103 103 The `Client` itself doesn't actually know what to do with operations. Instead, it sends them through ··· 115 115 unique `key`. 116 116 - This operation is sent into the **exchanges** and eventually ends up at the `fetchExchange` 117 117 (or a similar exchange) 118 - - The operation is sent to the API and a **result** comes back which is wrapped in an `OperationResult` 118 + - The operation is sent to the API and a **result** comes back, which is wrapped in an `OperationResult` 119 119 - The `Client` filters the `OperationResult` by the `operation.key` and — via a callback — gives us 120 120 a **stream of results**. 121 121 ··· 167 167 But, **what are streams?** 168 168 169 169 Generally we refer to _streams_ as abstractions that allow us to program with asynchronous events 170 - over time. Within the JavaScript context we're thinking specifically in terms of of 170 + over time. Within the context of JavaScript we're specifically thinking in terms of 171 171 [Observables](https://github.com/tc39/proposal-observable) 172 172 and [Reactive Programming with Observables.](http://reactivex.io/documentation/observable.html) 173 173 These concepts may sound initimidating, but from a high-level view what we're talking about can be 174 174 thought of as a combination of promises and iterables (e.g. arrays). We're dealing with multiple 175 - events but our callback is called over time. It's like calling `forEach` on an array but expecting 175 + events, but our callback is called over time. It's like calling `forEach` on an array but expecting 176 176 the results to come in asynchronously. 177 177 178 178 As a user, if we're using the one framework bindings that we've seen in [the "Basics"
+17 -16
docs/basics/core.md
··· 22 22 ## Installation 23 23 24 24 As we said above, if we are using bindings then those will already have installed `@urql/core` as 25 - they depend on it. They also all re-export all exports from `@urql/core`, so we can use those no 26 - matter which bindings we've installed. However, it's also possible to explicitly install 25 + they depend on it. They also all re-export all exports from `@urql/core`, so we can use those 26 + regardless of which bindings we've installed. However, it's also possible to explicitly install 27 27 `@urql/core` or use it standalone, e.g. in a Node.js environment. 28 28 29 29 ```sh ··· 111 111 `; 112 112 ``` 113 113 114 - This will all look familiar when coming from the `graphql-tag` package. The functionality is 115 - identical and the output is approximately the same. The two packages are also intercompatible. 116 - However, one small change that `@urql/core`'s implementation makes is that your fragment names don't 117 - have to be globally unique, since it's possible to create some one-off fragments every now and then. 114 + This usage will look familiar when coming from the `graphql-tag` package. The `gql` API is 115 + identical, and its output is approximately the same. The two packages are also intercompatible. 116 + However, one small change in `@urql/core`'s implementation is that your fragment names don't 117 + have to be globally unique, since it's possible to create some one-off fragments occasionally, 118 + especially for `@urql/exchange-graphcache`'s configuration. 118 119 It also pre-generates a "hash key" for the `DocumentNode` which is what `urql` does anyway, thus 119 120 avoiding some extra work compared to when the `graphql-tag` package is used with `urql`. 120 121 ··· 143 144 At the bare minimum we'll need to pass an API's `url` when we create a `Client` to get started. 144 145 145 146 Another common option is `fetchOptions`. This option allows us to customize the options that will be 146 - passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or 147 + passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object, or 147 148 a function returning an options object. 148 149 149 150 In the following example we'll add a token to each `fetch` request that our `Client` sends to our ··· 167 168 without it. However, another important option on the `Client` is the `exchanges` option. 168 169 169 170 This option passes a list of exchanges to the `Client`, which tell it how to execute our requests 170 - and how to cache data in a certain order. By default this will be populated with the list of 171 + and how to cache data in a certain order. By default, this will be populated with the list of 171 172 `defaultExchanges`. 172 173 173 174 ```js ··· 186 187 supports by adding new exchanges to this list. On [the "Architecture" page](../architecture.md) 187 188 we'll also learn more about what exchanges are and why they exist. 188 189 189 - For now it's sufficient for us to know that our requests are executed using the logic in the 190 + For now, it's enough for us to know that our requests are executed using the logic in the 190 191 exchanges in order. First, the `dedupExchange` deduplicates requests if we send the same queries 191 192 twice, the `cacheExchange` implements the default "document caching" behaviour (as we'll learn about 192 193 on the ["Document Caching"](./document-caching.md) page), and lastly the `fetchExchange` is ··· 218 219 219 220 In the above example we're executing a query on the client, are passing some variables and are 220 221 calling the `toPromise()` method on the return value to execute the request immediately and get the 221 - result as a promise. This may be useful when we don't plan on cancelling queries or we don't 222 + result as a promise. This may be useful when we don't plan on cancelling queries, or we don't 222 223 care about future updates to this data and are just looking to query a result once. 223 224 224 225 The same can be done for mutations by calling the `client.mutation` method instead of the 225 226 `client.query` method. 226 227 227 228 Similarly there's a way to read data from the cache synchronously, provided that the cache has 228 - received a result for a given query before. The `Client` has a `readQuery` method which is a 229 + received a result for a given query before. The `Client` has a `readQuery` method, which is a 229 230 shortcut for just that. 230 231 231 232 ```js ··· 279 280 ``` 280 281 281 282 This code example is similar to the one before. However, instead of sending a one-off query, we're 282 - subscribing to the query. Internally, this causes the `Client` to do the exact same, but the 283 + subscribing to the query. Internally, this causes the `Client` to do the same, but the 283 284 subscription means that our callback may be called repeatedly. We may get future results as well as 284 285 the first one. 285 286 ··· 287 288 immediately if our cache already has a result for the given query. The same principle applies here! 288 289 Our callback will be called synchronously if the cache already has a result. 289 290 290 - Once we're not interested in any results anymore we need to clean up after ourselves by calling 291 + Once we're not interested in any results anymore, we need to clean up after ourselves by calling 291 292 `unsubscribe`. This stops the subscription and makes sure that the `Client` doesn't actively update 292 293 the query anymore or refetches it. We can think of this pattern as being very similar to events or 293 294 event hubs. 294 295 295 - We're using [the Wonka library for our streams](https://wonka.kitten.sh/basics/background) which 296 + We're using [the Wonka library for our streams](https://wonka.kitten.sh/basics/background), which 296 297 we'll learn more about [on the "Architecture" page](./architecture.md). But we can think of this as 297 298 React's effects being called over time, or as `window.addEventListener`. 298 299 ··· 303 304 304 305 - [`CombinedError`](../api/core.md#combinederror) - our abstraction to combine one or more `GraphQLError`(s) and a `NetworkError` 305 306 - `makeResult` and `makeErrorResult` - utilities to create _Operation Results_ 306 - - [`createRequest`](../api/core.md#createrequest) - a utility function to create a request from a query and some variables (which 307 - generates a stable _Operation Key_) 307 + - [`createRequest`](../api/core.md#createrequest) - a utility function to create a request from a 308 + query, and some variables (which generate a stable _Operation Key_) 308 309 309 310 There are other utilities not mentioned here. Read more about the `@urql/core` API in the [API docs](../api/core.md). 310 311
+6 -7
docs/basics/document-caching.md
··· 5 5 6 6 # Document Caching 7 7 8 - By default `urql` uses a concept called _Document Caching_. It will avoid sending the same requests 8 + By default, `urql` uses a concept called _Document Caching_. It will avoid sending the same requests 9 9 to a GraphQL API repeatedly by caching the result of each query. 10 10 11 11 This works like the cache in a browser. `urql` creates a key for each request that is sent based on ··· 39 39 40 40 ## Request Policies 41 41 42 - The _request policy_ that is defined will alter what the default document cache does. By default the 42 + The _request policy_ that is defined will alter what the default document cache does. By default, the 43 43 cache will prefer cached results and will otherwise send a request, which is called `cache-first`. 44 44 In total there are four different policies that we can use: 45 45 ··· 63 63 64 64 ## Document Cache Gotchas 65 65 66 - This cache has a small trade-off! If we request a list of data and the API returns an empty list, 67 - the cache won't be able to see the `__typename` of said list and won't invalidate. 66 + This cache has a small trade-off! If we request a list of data, and the API returns an empty list, 67 + then the cache won't be able to see the `__typename` of said list and invalidate it. 68 68 69 69 There are two ways to fix this issue, supplying `additionalTypenames` to the context of your query or [switch to "Normalized Caching" 70 70 instead](../graphcache/normalized-caching.md). ··· 91 91 92 92 Now the cache will know when to invalidate this query even when the list is empty. 93 93 94 - We also have the possibility to use this for `mutations`. 95 - There are moments where a mutation can cause a side-effect on your server side and it needs 96 - to invalidate an additional entity. 94 + We may also use this feature for mutations, since occasionally mutations must invalidate data that 95 + isn't directly connected to a mutation by a `__typename`. 97 96 98 97 ```js 99 98 const [result, execute] = useMutation(`mutation($name: String!) { createUser(name: $name) }`);
+1 -1
docs/basics/errors.md
··· 16 16 - The `networkError` property will contain any error that stopped `urql` from making a network 17 17 request. 18 18 - The `graphQLErrors` property may be an array that contains [normalized `GraphQLError`s as they 19 - were returned in the `errors` array from a GraphQL API.](https://graphql.org/graphql-js/error/) 19 + were received in the `errors` array from a GraphQL API.](https://graphql.org/graphql-js/error/) 20 20 21 21 Additionally, the `message` of the error will be generated and combined from the errors for 22 22 debugging purposes.
+16 -16
docs/basics/react-preact.md
··· 14 14 15 15 ### Installation 16 16 17 - Installing `urql` is as quick as you'd expect and you won't need any other packages to get started 17 + Installing `urql` is as quick as you'd expect, and you won't need any other packages to get started 18 18 with at first. We'll install the package with our package manager of choice. 19 19 20 20 ```sh ··· 51 51 At the bare minimum we'll need to pass an API's `url` when we create a `Client` to get started. 52 52 53 53 Another common option is `fetchOptions`. This option allows us to customize the options that will be 54 - passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or 54 + passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object, or 55 55 a function returning an options object. 56 56 57 57 In the following example we'll add a token to each `fetch` request that our `Client` sends to our ··· 89 89 ); 90 90 ``` 91 91 92 - Now every component and element inside and under the `Provider` are able to use GraphQL queries that 92 + Now every component and element inside and under the `Provider` can use GraphQL queries that 93 93 will be sent to our API. 94 94 95 95 ## Queries 96 96 97 97 Both libraries offer a `useQuery` hook and a `Query` component. The latter accepts the same 98 - parameters but we won't cover it in this guide. [Look it up in the API docs if you prefer 98 + parameters, but we won't cover it in this guide. [Look it up in the API docs if you prefer 99 99 render-props components.](../api/urql.md#query-component) 100 100 101 101 ### Run a first query ··· 137 137 138 138 Here we have implemented our first GraphQL query to fetch todos. We see that `useQuery` accepts 139 139 options and returns a tuple. In this case we've set the `query` option to our GraphQL query. The 140 - tuple we then get in return is an array that contains a result object and a re-execute function. 140 + tuple we then get in return is an array that contains a result object, and a re-execute function. 141 141 142 - The result object contains several properties. The `fetching` field indicates whether we're currently 142 + The result object contains several properties. The `fetching` field indicates whether the hook is 143 143 loading data, `data` contains the actual `data` from the API's result, and `error` is set when either 144 144 the request to the API has failed or when our API result contained some `GraphQLError`s, which 145 145 we'll get into later on the ["Errors" page](./errors.md). ··· 174 174 `POST` request body that is sent to our GraphQL API. 175 175 176 176 Whenever the `variables` (or the `query`) option on the `useQuery` hook changes `fetching` will 177 - switch to `true` and a new request will be sent to our API, unless a result has already been cached 177 + switch to `true`, and a new request will be sent to our API, unless a result has already been cached 178 178 previously. 179 179 180 180 ### Pausing `useQuery` ··· 191 191 192 192 Let's pause the query we've just 193 193 written to not execute when these variables are empty, to prevent `null` variables from being 194 - executed. We can do this by means of setting the `pause` option to `true`: 194 + executed. We can do this by setting the `pause` option to `true`: 195 195 196 196 ```jsx 197 197 const Todos = ({ from, limit }) => { ··· 215 215 than just `query` and `variables`. Another option we should touch on is `requestPolicy`. 216 216 217 217 The `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By 218 - default this is set to `cache-first`, which means that we prefer to get results from our cache, but 218 + default, this is set to `cache-first`, which means that we prefer to get results from our cache, but 219 219 are falling back to sending an API request. 220 220 221 221 Request policies aren't specific to `urql`'s React API, but are a common feature in its core. [You ··· 226 226 227 227 The `useQuery` hook updates and executes queries whenever its inputs, like the `query` or 228 228 `variables` change, but in some cases we may find that we need to programmatically trigger a new 229 - query. This is the purpose of the `reexecuteQuery` function which is the second item in the tuple 229 + query. This is the purpose of the `reexecuteQuery` function, which is the second item in the tuple 230 230 that `useQuery` returns. 231 231 232 232 Triggering a query programmatically may be useful in a couple of cases. It can for instance be used 233 - to refresh data that is currently being displayed. In these cases we may also override the 234 - `requestPolicy` of our query just once and set it to `network-only` to skip the cache. 233 + to refresh the hook's data. In these cases we may also override the `requestPolicy` of our query just 234 + once and set it to `network-only` to skip the cache. 235 235 236 236 ```jsx 237 237 const Todos = ({ from, limit }) => { ··· 259 259 ## Mutations 260 260 261 261 Both libraries offer a `useMutation` hook and a `Mutation` component. The latter accepts the same 262 - parameters but we won't cover it in this guide. [Look it up in the API docs if you prefer 262 + parameters, but we won't cover it in this guide. [Look it up in the API docs if you prefer 263 263 render-props components.](../api/urql.md#mutation-component) 264 264 265 265 ### Sending a mutation ··· 293 293 ### Using the mutation result 294 294 295 295 When calling our `updateTodo` function we have two ways of getting to the result as it comes back 296 - from our API. We can either use the first value of the returned tuple — our `updateTodoResult` — or 296 + from our API. We can either use the first value of the returned tuple, our `updateTodoResult`, or 297 297 we can use the promise that `updateTodo` returns. 298 298 299 299 ```jsx ··· 312 312 ``` 313 313 314 314 The result is useful when your UI has to display progress on the mutation, and the returned 315 - promise is particularly useful when you're adding side-effects that run after the mutation has 315 + promise is particularly useful when you're adding side effects that run after the mutation has 316 316 completed. 317 317 318 318 ### Handling mutation errors ··· 345 345 ## Reading on 346 346 347 347 This concludes the introduction for using `urql` with React or Preact. The rest of the documentation 348 - is mostly framework-agnostic and will apply to either `urql` in general or the `@urql/core` package, 348 + is mostly framework-agnostic and will apply to either `urql` in general, or the `@urql/core` package, 349 349 which is the same between all framework bindings. Hence, next we may want to learn more about one of 350 350 the following to learn more about the internals: 351 351
+8 -8
docs/basics/svelte.md
··· 108 108 109 109 The `operationStore` function creates a [Svelte Writable store](https://svelte.dev/docs#writable). 110 110 You can use it to initialise a data container in `urql`. This store holds on to our query inputs, 111 - like the GraphQL query and variables, which we can change to launch new queries, and also exposes 111 + like the GraphQL query and variables, which we can change to launch new queries. It also exposes 112 112 the query's eventual result, which we can then observe. 113 113 114 114 ### Run a first query ··· 213 213 <button on:click={nextPage}>Next page<button></button></button> 214 214 ``` 215 215 216 - The `operationStore` provides getters too so it's also possible for us to pass `todos` around and 216 + The `operationStore` provides getters as well, so it's also possible for us to pass `todos` around and 217 217 update `todos.variables` or `todos.query` directly. Both, updating `todos.variables` and 218 218 `$todos.variables` in a component for instance, will cause `query` to pick up the update and execute 219 219 our changes. ··· 225 225 started at will. Instead, the `query`'s third argument, the `context`, may have an added `pause` 226 226 option that can be set to `true` to temporarily _freeze_ all changes and stop requests. 227 227 228 - For instance we may start out with a paused store and then unpause it once a callback is invoked: 228 + For instance, we may start out with a paused store and then unpause it once a callback is invoked: 229 229 230 230 ```html 231 231 <script> ··· 260 260 most interesting option the `context` may contain is `requestPolicy`. 261 261 262 262 The `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By 263 - default this is set to `cache-first`, which means that we prefer to get results from our cache, but 263 + default, this is set to `cache-first`, which means that we prefer to get results from our cache, but 264 264 are falling back to sending an API request. 265 265 266 266 In total there are four different policies that we can use: ··· 301 301 ... 302 302 ``` 303 303 304 - As we can see, the `requestPolicy` is easily changed here and we can read our `context` option back 304 + As we can see, the `requestPolicy` is easily changed, and we can read our `context` option back 305 305 from `todos.context`, just as we can check `todos.query` and `todos.variables`. Updating 306 306 `operationStore.context` can be very useful to also refetch queries, as we'll see in the next 307 307 section. ··· 313 313 The default caching approach in `@urql/svelte` typically takes care of updating queries on the fly 314 314 quite well and does so automatically. Sometimes it may be necessary though to refetch data and to 315 315 execute a query with a different `context`. Triggering a query programmatically may be useful in a 316 - couple of cases. It can for instance be used to refresh data that is currently being displayed. 316 + couple of cases. It can for instance be used to refresh data. 317 317 318 318 We can trigger a new query update by changing out the `context` of our `operationStore`. 319 319 ··· 351 351 ## Mutations 352 352 353 353 The `mutation` function isn't dissimilar from the `query` function but is triggered manually and 354 - can accept a [`GraphQLRequest` object](../api/core.md#graphqlrequest) too while also supporting our 354 + can accept a [`GraphQLRequest` object](../api/core.md#graphqlrequest), while also supporting our 355 355 trusty `operationStore`. 356 356 357 357 ### Sending a mutation ··· 473 473 ## Reading on 474 474 475 475 This concludes the introduction for using `urql` with Svelte. The rest of the documentation 476 - is mostly framework-agnostic and will apply to either `urql` in general or the `@urql/core` package, 476 + is mostly framework-agnostic and will apply to either `urql` in general, or the `@urql/core` package, 477 477 which is the same between all framework bindings. Hence, next we may want to learn more about one of 478 478 the following to learn more about the internals: 479 479
+8 -7
docs/comparison.md
··· 5 5 6 6 # Comparison 7 7 8 - > This comparison page aims to be accurate, unbiased, and up-to-date. If you see any information that 8 + > This comparison page aims to be detailed, unbiased, and up-to-date. If you see any information that 9 9 > may be inaccurate or could be improved otherwise, please feel free to suggest changes. 10 10 11 11 The most common question that you may encounter with GraphQL is what client to choose when you are 12 - getting started. We aim to provide an unbiased and accurate comparison of several options on this 12 + getting started. We aim to provide an unbiased and detailed comparison of several options on this 13 13 page, so that you can make an **informed decision**. 14 14 15 15 All options come with several drawbacks and advantages, and all of these clients have been around 16 16 for a while now. A little known fact is that `urql` in its current form and architecture has already 17 - existed since February of 2019, and its normalized cache has been around since September 2019. 17 + existed since February 2019, and its normalized cache has been around since September 2019. 18 18 19 19 Overall, we would recommend to make your decision based on whether your required features are 20 20 supported, which patterns you'll use (or restrictions thereof), and you may want to look into 21 - whether all of the parts and features you're interested in are well maintained. 21 + whether all the parts and features you're interested in are well maintained. 22 22 23 23 ## Comparison by Features 24 24 ··· 60 60 61 61 Typically these are all additional addon features that you may expect from a GraphQL client, no 62 62 matter which framework you use it with. It's worth mentioning that all three clients support some 63 - kind of extensibility API which allows you to change when and how queries are sent to an API. These 63 + kind of extensibility API, which allows you to change when and how queries are sent to an API. These 64 64 are easy to use primitives particularly in Apollo, with links, and in `urql` with exchanges. The 65 65 major difference in `urql` is that all caching logic is abstracted in exchanges too, which makes 66 66 it easy to swap the caching logic or other behavior out (and hence makes `urql` slightly more ··· 138 138 `@urql/exchange-graphcache` we chose to include it as a feature since it also strengthened other 139 139 guarantees that the cache makes. 140 140 141 - Relay does in fact have similar guarantees as [`urql`'s Commutativity Guarantees](./graphcache/under-the-hood.md) 141 + Relay does in fact have similar guarantees as [`urql`'s Commutativity 142 + Guarantees](./graphcache/under-the-hood.md), 142 143 which are more evident when applying list updates out of order under more complex network 143 144 conditions. 144 145 ··· 155 156 156 157 - Parts of the `graphql` package tree-shake away and may also be replaced (e.g. `parse`) 157 158 - All packages in `urql` reuse parts of `@urql/core` and `wonka`, which means adding all their total 158 - sizes up doesn't give you an accurate result. 159 + sizes up doesn't give you a correct result of their total expected bundle size. 159 160 - These sizes may change drastically given the code you write and add yourself, but can be managed 160 161 via precompilation (e.g. with `babel-plugin-graphql-tag` or GraphQL Code Generator for Apollo and 161 162 `urql`)
+5 -5
docs/graphcache/README.md
··· 5 5 6 6 # Graphcache 7 7 8 - In `urql`, caching is fully configurable via [exchanges](../architecture.md) and the default 8 + In `urql`, caching is fully configurable via [exchanges](../architecture.md), and the default 9 9 `cacheExchange` in `urql` offers a ["Document Cache"](../basics/document-caching.md), which is 10 - sufficient for sites that heavily rely and render static content. However as an app grows more 10 + usually enough for sites that heavily rely on static content. However as an app grows more 11 11 complex it's likely that the data and state that `urql` manages, will also grow more complex and 12 12 introduce interdependencies between data. 13 13 ··· 15 15 how [data is often structured in 16 16 Redux.](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape/) 17 17 18 - In `urql`, normalized caching is an opt-in feature which is provided by the 18 + In `urql`, normalized caching is an opt-in feature, which is provided by the 19 19 `@urql/exchange-graphcache` package, _Graphcache_ for short. 20 20 21 21 ## Features 22 22 23 - The following pages introduce different features in _Graphcache_ which together make it a compelling 23 + The following pages introduce different features in _Graphcache_, which together make it a compelling 24 24 alternative to the standard [document cache](../basics/document-caching.md) that `urql` uses by 25 25 default. 26 26 27 27 - 🔁 [**Fully reactive, normalized caching.**](./normalized-caching.md) _Graphcache_ stores data in 28 - a normalized data structure. Query, mutation, and subscription results may update one another if 28 + a normalized data structure. Query, mutation and subscription results may update one another if 29 29 they share data, and the app will rerender or refetch data accordingly. This often allows your app 30 30 to make fewer API requests, since data may already be in the cache. 31 31 - 💾 [**Custom cache resolvers**](./local-resolvers.md) Since all queries are fully resolved in the
+32 -32
docs/graphcache/cache-updates.md
··· 11 11 that is found in a result will be stored under the entity's key. 12 12 13 13 A query's result is represented as a graph, which can also be understood as a tree structure, 14 - starting from the root `Query` entity which then connects to other entities via links, which are 14 + starting from the root `Query` entity, which then connects to other entities via links, which are 15 15 relations stored as keys, where each entity has records that store scalar values, which are the 16 16 tree's leafs. On the previous page, on ["Local Resolvers"](./local-resolvers.md), we've seen how 17 17 resolvers can be attached to fields to manually resolve other entities (or transform record fields). ··· 23 23 [quote](./normalized-caching.md/#storing-normalized-data): 24 24 25 25 > Any mutation or subscription can also be written to this data structure. Once Graphcache finds a 26 - > keyable entity in their results it's written to its relational table which may update other queries 27 - > in our application. 26 + > keyable entity in their results it's written to its relational table, which may update other 27 + > queries in our application. 28 28 29 29 This means that mutations and subscriptions still write and update entities in the cache. These 30 - updates are then reflected on all queries that our app currently uses. However, there are 31 - limitations to this. While resolvers can be used to passively change data for queries, for mutations 30 + updates are then reflected on all active queries that our app uses. However, there are limitations to this. 31 + While resolvers can be used to passively change data for queries, for mutations 32 32 and subscriptions we sometimes have to write **updaters** to update links and relations. 33 33 This is often necessary when a given mutation or subscription deliver a result that is more granular 34 34 than the cache needs to update all affected entities. ··· 62 62 An "updater" may be attached to a `Mutation` or `Subscription` field and accepts four positional 63 63 arguments, which are the same as [the resolvers' arguments](./local-resolvers.md): 64 64 65 - - `result`: The full API result that's currently being written to the cache. Typically we'd want to 65 + - `result`: The full API result that's being written to the cache. Typically we'd want to 66 66 avoid coupling by only looking at the current field that the updater is attached to, but it's 67 67 worth noting that we can access any part of the result. 68 68 - `args`: The arguments that the field has been called with, which will be replaced with an empty ··· 70 70 - `cache`: The `cache` instance, which gives us access to methods allowing us to interact with the 71 71 - local cache. Its full API can be found [in the API docs](../api/graphcache.md#cache). On this page 72 72 we use it frequently to read from and write to the cache. 73 - - `info`: This argument shouldn't be used frequently but it contains running information about the 73 + - `info`: This argument shouldn't be used frequently, but it contains running information about the 74 74 traversal of the query document. It allows us to make resolvers reusable or to retrieve 75 75 information about the entire query. Its full API can be found [in the API 76 76 docs](../api/graphcache.md#info). 77 77 78 78 The cache updaters return value is disregarded (and typed as `void` in TypeScript), which makes any 79 - method that they call on the `cache` instance a side-effect, which may trigger additional cache 79 + method that they call on the `cache` instance a side effect, which may trigger additional cache 80 80 changes and updates all affected queries as we modify them. 81 81 82 82 ## Manually updating entities ··· 144 144 > [the `gql` tag function](../api/core.md#gql) because `writeFragment` only accepts 145 145 > GraphQL `DocumentNode`s as inputs, and not strings. 146 146 147 - ### Cache Updates outside of updates 147 + ### Cache Updates outside updates 148 148 149 - Cache updates are **not** possible outside of `updates`. If we attempt to store the `cache` in a 150 - variable and call its methods outside of any `updates` functions (or functions, like `resolvers`) 149 + Cache updates are **not** possible outside `updates`. If we attempt to store the `cache` in a 150 + variable and call its methods outside any `updates` functions (or functions, like `resolvers`) 151 151 then Graphcache will throw an error. 152 152 153 - Methods like these cannot be called outside of the `cacheExchange`'s `updates` functions, because 153 + Methods like these cannot be called outside the `cacheExchange`'s `updates` functions, because 154 154 all updates are isolated to be _reactive_ to mutations and subscription events. In Graphcache, 155 155 out-of-band updates aren't permitted because the cache attempts to only represent the server's 156 156 state. This limitation keeps the data of the cache true to the server data we receive from API 157 157 results and makes its behaviour much more predictable. 158 158 159 - If we still manage to call any of the cache's methods outside of its callbacks in its configuration, 159 + If we still manage to call any of the cache's methods outside its callbacks in its configuration, 160 160 we will receive [a "(2) Invalid Cache Call" error](./errors.md#2-invalid-cache-call). 161 161 162 162 ## Updating lists or links ··· 202 202 Here we use the `cache.updateQuery` method, which is similar to the `cache.readQuery` method that 203 203 we've seen on the "Local Resolvers" page before](./local-resolvers.md#reading-a-query). 204 204 205 - This method accepts a callback which will give us the `data` of the query, as read from the locally 206 - cached data and we may return an updated version of this data. While we may want to instinctively 205 + This method accepts a callback, which will give us the `data` of the query, as read from the locally 206 + cached data, and we may return an updated version of this data. While we may want to instinctively 207 207 opt for immutably copying and modifying this data, we're actually allowed to mutate it directly, 208 208 since it's just a copy of the data that's been read by the cache. 209 209 210 210 This `data` may also be `null` if the cache doesn't actually have enough locally cached information 211 211 to fulfil the query. This is important because resolvers aren't actually applied to cache methods in 212 - updaters. All resolvers are ignored so it becomes impossible to accidentally commit transformed data 212 + updaters. All resolvers are ignored, so it becomes impossible to accidentally commit transformed data 213 213 to our cache. We could safely add a resolver for `Todo.createdAt` and wouldn't have to worry about 214 214 an updater accidentally writing it to the cache's internal data structure. 215 215 ··· 219 219 the cache. However, we've used a rather simple example when we've looked at a single list on a known 220 220 field. 221 221 222 - In many schemas pagination is quite common and when we for instance delete a todo then knowing which 223 - list to update becomes unknowable. We cannot know ahead of time how many pages (and using which 224 - variables) we've already accessed. This knowledge in fact _shouldn't_ be available to Graphcache. 225 - Querying the `Client` is an entirely separate concern that's often colocated with some part of our 222 + In many schemas pagination is quite common, and when we for instance delete a todo then knowing the 223 + lists to update becomes unknowable. We cannot know ahead of time how many pages (and its variables) 224 + we've already accessed. This knowledge in fact _shouldn't_ be available to Graphcache. Querying the 225 + `Client` is an entirely separate concern that's often colocated with some part of our 226 226 UI code. 227 227 228 228 ```graphql ··· 231 231 } 232 232 ``` 233 233 234 - Suppose we have the above mutation which deletes a `Todo` entity by its ID. Our app may query a list 234 + Suppose we have the above mutation, which deletes a `Todo` entity by its ID. Our app may query a list 235 235 of these items over many pages with separate queries being sent to our API, which makes it hard to 236 - know which fields should be checked: 236 + know the fields that should be checked: 237 237 238 238 ```graphql 239 239 query PaginatedTodos ($skip: Int) { ··· 244 244 } 245 245 ``` 246 246 247 - Instead, we can **introspect an entity's fields** to find out dynamically which fields we may want 248 - to update. This is possible thanks to [the `cache.inspectFields` 249 - method](../api/graphcache.md#inspectfields). This method accepts a key or a keyable entity like the 247 + Instead, we can **introspect an entity's fields** to find the fields we may want to update 248 + dynamically. This is possible thanks to [the `cache.inspectFields` 249 + method](../api/graphcache.md#inspectfields). This method accepts a key, or a keyable entity like the 250 250 `cache.keyOfEntity` method that [we've seen on the "Local Resolvers" 251 251 page](./local-resolvers.md#resolving-by-keys) or the `cache.resolve` method's first argument. 252 252 ··· 290 290 - `arguments`: The arguments for the given field, since each field that accepts arguments can be 291 291 accessed multiple times with different arguments. In this example we're looking at 292 292 `arguments.skip` to find all unique pages. 293 - - `fieldKey`: This is the field's key which can come in useful to retrieve a field using 293 + - `fieldKey`: This is the field's key, which can come in useful to retrieve a field using 294 294 `cache.resolve(entityKey, fieldKey)` to prevent the arguments from having to be stringified 295 295 repeatedly. 296 296 ··· 326 326 327 327 We may use the cache's [`cache.invalidate` method](../api/graphcache.md#invalidate) to either 328 328 invalidate entire entities or individual fields. It has the same signature as [the `cache.resolve` 329 - method](../api/graphcache.md#resolve) which we've already seen [on the "Local Resolvers" page as 329 + method](../api/graphcache.md#resolve), which we've already seen [on the "Local Resolvers" page as 330 330 well](./local-resolvers.md#resolving-other-fields). We can simplify the previous update we've written 331 331 with a call to `cache.invalidate`: 332 332 ··· 391 391 If we know what result a mutation may return, why wait for the GraphQL API to fulfill our mutations? 392 392 393 393 Additionally to the `updates` configuration we may also pass an `optimistic` option to the 394 - `cacheExchange` which is a factory function using which we can create a "virtual" result for a 394 + `cacheExchange` which is a factory function using, which we can create a "virtual" result for a 395 395 mutation. This temporary result can be applied immediately to the cache to give our users the 396 396 illusion that mutations were executed immediately, which is a great method to reduce waiting time 397 397 and to make our apps feel snappier. ··· 413 413 - `cache`: The `cache` instance, which gives us access to methods allowing us to interact with the 414 414 - local cache. Its full API can be found [in the API docs](../api/graphcache.md#cache). On this page 415 415 we use it frequently to read from and write to the cache. 416 - - `info`: This argument shouldn't be used frequently but it contains running information about the 416 + - `info`: This argument shouldn't be used frequently, but it contains running information about the 417 417 traversal of the query document. It allows us to make resolvers reusable or to retrieve 418 418 information about the entire query. Its full API can be found [in the API 419 419 docs](../api/graphcache.md#info). 420 420 421 421 The usual `parent` argument isn't present since optimistic functions don't have any server data to 422 422 handle or deal with and instead create this data. When a mutation is run that contains one or more 423 - optimistic mutation fields, Graphcache picks these up and generates immediate changes which it 423 + optimistic mutation fields, Graphcache picks these up and generates immediate changes, which it 424 424 applies to the cache. The `resolvers` functions also trigger as if the results were real server 425 425 results. 426 426 ··· 464 464 Sometimes it's not possible for us to retrieve all data that an optimistic update requires to create 465 465 a "fake result" from the cache or from all existing variables. 466 466 467 - This is why Graphcache allows for a small escape hatch for these scenarios which allows us to access 468 - additional variables which we may want to pass from our UI code to the mutation. For instance, given 467 + This is why Graphcache allows for a small escape hatch for these scenarios, which allows us to access 468 + additional variables, which we may want to pass from our UI code to the mutation. For instance, given 469 469 a mutation like the following we may add more variables than the mutation specifies: 470 470 471 471 ```graphql
+15 -15
docs/graphcache/errors.md
··· 7 7 8 8 **This document lists out all errors and warnings in `@urql/exchange-graphcache`.** 9 9 10 - Any unexpected behaviour, condition, or error will be marked by an error or warning 11 - in development, which will output a helpful little message. Sometimes however, this 12 - message may not actually tell you everything about what's going on. 10 + Any unexpected behaviour or condition will be marked by an error or warning 11 + in development. This will output as a helpful little message. Sometimes, however, this 12 + message may not actually tell you about everything that's going on. 13 13 14 14 This is a supporting document that explains every error and attempts to give more 15 15 information on how you may be able to fix some issues or avoid these errors/warnings. ··· 17 17 ## (1) Invalid GraphQL document 18 18 19 19 > Invalid GraphQL document: All GraphQL documents must contain an OperationDefinition 20 - > node for a query, subscription, or mutation. 20 + > node for a query, subscription or mutation. 21 21 22 22 There are multiple places where you're passing in GraphQL documents, either through 23 23 methods on `Cache` (e.g. `cache.updateQuery`) or via `urql` using the `Client` or 24 24 hooks like `useQuery`. 25 25 26 - Your queries must always contain a main operation, so either a query, mutation, or 26 + Your queries must always contain a main operation, one of: query, mutation, or 27 27 subscription. This error occurs when this is missing, because the `DocumentNode` 28 28 is maybe empty or only contains fragments. 29 29 ··· 33 33 > operations like write or query, or as part of its resolvers, updaters, 34 34 > or optimistic configs. 35 35 36 - If you're somehow accessing the `Cache` (an instance of `Store`) outside of any 36 + If you're somehow accessing the `Cache` (an instance of `Store`) outside any 37 37 of the usual operations then this error will be thrown. 38 38 39 39 Please make sure that you're only calling methods on the `cache` as part of 40 - configs that you pass to your `cacheExchange`. Outside of these functions the cache 40 + configs that you pass to your `cacheExchange`. Outside these functions the cache 41 41 must not be changed. 42 42 43 43 However when you're not using the `cacheExchange` and are trying to use the ··· 45 45 initialised correctly. 46 46 47 47 This is a safe-guard to prevent any asynchronous work to take place, or to 48 - avoid mutating the cache outside of any normal operation. 48 + avoid mutating the cache outside any normal operation. 49 49 50 50 ## (3) Invalid Object type 51 51 ··· 74 74 Check whether your schema is up-to-date or whether you're using an invalid 75 75 field somewhere, maybe due to a typo. 76 76 77 - As the warning states, this won't lead any operation to abort or an error 77 + As the warning states, this won't lead any operation to abort, or an error 78 78 to be thrown! 79 79 80 80 ## (5) Invalid Abstract type ··· 192 192 193 193 As data is written to the cache, this warning is issued when `undefined` is encountered. 194 194 GraphQL results should never contain an `undefined` value, so this warning will let you 195 - know which part of your result did contain `undefined`. 195 + know the part of your result that did contain `undefined`. 196 196 197 197 ## (14) Couldn't find \_\_typename when writing. 198 198 ··· 215 215 > If this is intentional, create a `keys` config for `???` that always returns null. 216 216 217 217 This error occurs when the cache can't generate a key for an entity. The key 218 - would then effectively be `null` and the entity won't be cached by a key. 218 + would then effectively be `null`, and the entity won't be cached by a key. 219 219 220 220 Conceptually this means that an entity won't be normalised but will indeed 221 221 be cached by the parent's key and field, which is displayed in the first ··· 225 225 226 226 But if your entity at that place doesn't have any `id` fields, then you may 227 227 have to create a custom `keys` config. This `keys` function either needs to 228 - return a unique ID for your entity or it needs to explicitly return `null` to silence 228 + return a unique ID for your entity, or it needs to explicitly return `null` to silence 229 229 this warning. 230 230 231 231 ## (16) Heuristic Fragment Matching ··· 259 259 `@populate` directive to fields it first checks whether the type is valid and 260 260 exists on the schema. 261 261 262 - If the field does not have sufficient type information because it doesn't exist 262 + If the field does not have enough type information because it doesn't exist 263 263 on the schema or does not match expectations then this warning is logged. 264 264 265 265 Check whether your schema is up-to-date or whether you're using an invalid ··· 303 303 304 304 ## (21) Invalid mutation 305 305 306 - > Invalid mutation field `???` is not in the defined schema but the `updates` option is referencing it. 306 + > Invalid mutation field `???` is not in the defined schema, but the `updates` option is referencing it. 307 307 308 308 When you're passing an introspected schema to the cache exchange, it is 309 309 able to check whether your `opts.updates.Mutation` is valid. ··· 313 313 314 314 ## (22) Invalid subscription 315 315 316 - > Invalid subscription field: `???` is not in the defined schema but the `updates` option is referencing it. 316 + > Invalid subscription field: `???` is not in the defined schema, but the `updates` option is referencing it. 317 317 318 318 When you're passing an introspected schema to the cache exchange, it is 319 319 able to check whether your `opts.updates.Subscription` is valid.
+9 -9
docs/graphcache/local-resolvers.md
··· 51 51 - `args`: The arguments that the field is being called with, which will be replaced with an empty 52 52 object if the field hasn't been called with any arguments. For example, if the field is queried as 53 53 `name(capitalize: true)` then `args` would be `{ capitalize: true }`. 54 - - `cache`: Unlike in GraphQL.js this will not be the context but a `cache` instance, which gives us 54 + - `cache`: Unlike in GraphQL.js this will not be the context, but a `cache` instance, which gives us 55 55 access to methods allowing us to interact with the local cache. Its full API can be found [in the 56 56 API docs](../api/graphcache.md#cache). 57 - - `info`: This argument shouldn't be used frequently but it contains running information about the 57 + - `info`: This argument shouldn't be used frequently, but it contains running information about the 58 58 traversal of the query document. It allows us to make resolvers reusable or to retrieve 59 59 information about the entire query. Its full API can be found [in the API 60 60 docs](../api/graphcache.md#info). ··· 96 96 We may also run into situations where we'd like to generalise the resolver and not make it dependent 97 97 on the exact field it's being attached to. In these cases, the [`info` 98 98 object](../api/graphcache.md#info) can be very helpful as it provides us information about the 99 - current query traversal and which part of the query document the cache is currently processing. The 100 - `info.fieldName` property is one of these properties and lets us know which field the resolver is 101 - currently operating on. Hence, we can create a reusable resolver like so: 99 + current query traversal, and the part of the query document the cache is processing. The 100 + `info.fieldName` property is one of these properties and lets us know the field that the resolver is 101 + operating on. Hence, we can create a reusable resolver like so: 102 102 103 103 ```js 104 104 const transformToDate = (parent, _args, _cache, info) => ··· 176 176 ``` 177 177 178 178 The `__typename` field is required. Graphcache will [use its keying 179 - logic](./normalized-caching.md#custom-keys-and-non-keyable-entities) and your custom `keys` 179 + logic](./normalized-caching.md#custom-keys-and-non-keyable-entities), and your custom `keys` 180 180 configuration to generate a key for this entity and will then be able to look this entity up in its 181 181 local cache. As with regular queries, the resolver is known to return a link since the `todo(id: 182 182 $id) { id }` will be used with a selection set, querying fields on the entity. ··· 215 215 216 216 ## Resolving other fields 217 217 218 - In the above two examples we've seen how a resolver can replace Graphcache's logic which usually 218 + In the above two examples we've seen how a resolver can replace Graphcache's logic, which usually 219 219 reads links and records only from its locally cached data. We've seen how a field on a record can 220 220 use `parent[fieldName]` to access its cached record value and transform it and how a resolver for a 221 221 link can return a partial entity [or a key](#resolving-by-keys). ··· 236 236 237 237 - `entity`: This is the entity on which we'd like to access a field. We may either pass a keyable, 238 238 partial entity, e.g. `{ __typename: 'Todo', id: 1 }` or a key. It takes the same inputs as [the 239 - `cache.keyOfEntity` method](../api/graphcache.md#keyofentity) which we've seen earlier in the 239 + `cache.keyOfEntity` method](../api/graphcache.md#keyofentity), which we've seen earlier in the 240 240 ["Resolving by keys" section](#resolving-by-keys). It also accepts `null` which causes it to 241 241 return `null`, which is useful for chaining multiple `resolve` calls for deeply accessing a field. 242 242 - `fieldName`: This is the field's name we'd like to access. If we're looking for the record on ··· 381 381 382 382 ### Reading a query 383 383 384 - At any point, the `cache` allows us to read entirely separate queries in our resolvers which starts 384 + At any point, the `cache` allows us to read entirely separate queries in our resolvers, which starts 385 385 a separate virtual operation in our resolvers. When we call `cache.readQuery` with a query and 386 386 variables we can execute an entirely new GraphQL query against our cached data: 387 387
+3 -3
docs/graphcache/offline.md
··· 6 6 # Offline Support 7 7 8 8 _Graphcache_ allows you to build an offline-first app with built-in offline and persistence support, 9 - by means of adding a `storage` interface. In combination with its [Schema 9 + by adding a `storage` interface. In combination with its [Schema 10 10 Awareness](./schema-awareness.md) support and [Optimistic 11 11 Updates](./cache-updates.md#optimistic-updates) this can be used to build an application that 12 12 serves cached data entirely from memory when a user's device is offline and still display ··· 55 55 `offlineExchange`. The `storage` is an adapter that contains methods for storing cache data in a 56 56 persisted storage interface on the user's device. 57 57 58 - By default we can use the default storage option that `@urql/exchange-graphcache` comes with. This 58 + By default, we can use the default storage option that `@urql/exchange-graphcache` comes with. This 59 59 default storage uses [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) to 60 60 persist the cache's data. We can use this default storage by importing the `makeDefaultStorage` 61 61 function from `@urql/exchange-graphcache/default-storage`. ··· 121 121 have different strategies for dealing with this. 122 122 123 123 [The API docs list the entire interface for the `storage` option.](../api/graphcache.md#storage-option) 124 - There we can see which methods we need to implement to implement a custom storage engine. 124 + There we can see the methods we need to implement to implement a custom storage engine. 125 125 126 126 Following is an example of the simplest possible storage engine, which uses the browser's 127 127 [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage).
+6 -6
docs/graphcache/schema-awareness.md
··· 7 7 8 8 Previously, [on the "Normalized Caching" page](./normalized-caching.md) we've seen how Graphcache 9 9 stores normalized data in its store and how it traverses GraphQL documents to do so. What we've seen 10 - is that just using the GraphQL document for traversal and the `__typename` introspection field 10 + is that just using the GraphQL document for traversal, and the `__typename` introspection field 11 11 Graphcache is able to build a normalized caching structure that keeps our application up-to-date 12 12 across API results, allows it to store data by entities and keys, and provides us configuration 13 13 options to write [manual cache updates](./cache-updates.md) and [local ··· 40 40 - Fragments will be matched deterministically: A fragment can be written to be on an interface type 41 41 or multiple fragments can be spread for separate union'ed types in a selection set. In many cases, 42 42 if Graphcache doesn't have any schema information then it won't know what possible types a field 43 - can return and may sometimes make a best guess and [issue a 43 + can return and may sometimes make a guess and [issue a 44 44 warning](./errors.md#16-heuristic-fragment-matching). If we pass Graphcache a `schema` then it'll 45 45 be able to match fragments deterministically. 46 46 - A schema may have non-default names for its root types; `Query`, `Mutation`, and `Subscription`. ··· 51 51 start checking whether any of the configuration options actually don't exist, maybe because we've 52 52 typo'd them. This is a small detail but can make a large different in a longer configuration. 53 53 - Lastly; a schema contains information on **which fields are optional or required**. When 54 - Graphcache has a schema it knows which fields can be made optional and it'll be able to generate 54 + Graphcache has a schema it knows optional fields that may be left out, and it'll be able to generate 55 55 "partial results". 56 56 57 57 ### Partial Results 58 58 59 59 As we navigate an app that uses Graphcache we may be in states where some of our data is already 60 - cached and some isn't. Graphcache normalizes data and stores it in tables for links and records for 60 + cached while some aren't. Graphcache normalizes data and stores it in tables for links and records for 61 61 each entity, which means that sometimes it can maybe even execute a query against its cache that it 62 62 hasn't sent to the API before. 63 63 ··· 71 71 before it sent an API result.](../assets/partial-results.png) 72 72 73 73 Without a `schema` and information on which fields are optional, Graphcache will consider a "partial 74 - result" as a cache miss. If we don't have all of the information for a query then we can't execute 74 + result" as a cache miss. If we don't have all the information for a query then we can't execute 75 75 it against the locally cached data after all. However, an API's schema contains information on which 76 - fields are required and which fields are optional, and if our apps are typed with this schema and 76 + fields are required and optional, and if our apps are typed with this schema and 77 77 TypeScript, can't we then use and handle these partial results before a request is sent to the API? 78 78 79 79 This is the idea behind "Schema Awareness" and "Partial Results". When Graphcache has `schema`
+1 -1
docs/showcase.md
··· 6 6 # Showcase 7 7 8 8 `urql` wouldn't be the same without our growing and loving community of users, 9 - maintainers, and supporters. This page is specifically dedicated to all of you! 9 + maintainers and supporters. This page is specifically dedicated to all of you! 10 10 11 11 ## Used by folks at 12 12