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

Configure Feed

Select the types of activity you want to include in your feed.

(docs) - split up basics by bindings (#1218)

* start splitting up

* remove preludes

* add titles

* Apply suggestions from code review

Co-authored-by: Phil Pluckthun <phil@kitten.sh>

* Move concepts/core-package.md to basics/node.md and rename

* Move "Document Caching" and "Errors" to "Concepts"

* Update Overview page

* (docs) - Redirects (#1318)

* try out redirects

* Update static.config.js

* Update static.config.js

* Update static.config.js

* Add outro sections to each "Basics" page

* Update redirects

* Update internal links and references

- To React/Preact/Vue/Svelte pages
- To Request Policies (content moved to Document Caching)
- To Document Caching
- To Errors

Co-authored-by: Phil Pluckthun <phil@kitten.sh>

authored by

Jovi De Croock
Phil Pluckthun
and committed by
GitHub
2b4557da 832d9fd5

+1741 -1772
+26 -38
docs/README.md
··· 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 14 - pages through ["Document Caching"](./basics/document-caching.md) as well as dynamic and data-heavy 14 + pages through ["Document Caching"](./concepts/document-caching.md) as well as dynamic and data-heavy 15 15 apps through ["Normalized Caching"](./graphcache/normalized-caching.md). 16 16 17 - ## Constituent Parts 18 - 19 - `urql` can be understood as a collection of connected parts and packages. When [getting started](./basics/getting-started.md) we only need to install a single package for our 20 - framework of choice. We're then able to declaratively send GraphQL requests to our API. 21 - 22 - All framework packages — like `urql` (for React), `@urql/preact`, `@urql/svelte`, and `@urql/vue` — 23 - wrap the [core package, `@urql/core`](./concepts/core-package.md), which we can imagine as the brain 24 - of `urql` with most of its logic. 25 - 26 - As we progress with implementing `urql` into our application, we're later able to extend it by 27 - adding ["addon packages", which we call _Exchanges_](./concepts/exchanges.md) 17 + `urql` can be understood as a collection of connected parts and packages. 18 + When we only need to install a single package for our framework of choice. We're then able to 19 + declaratively send GraphQL requests to our API. All framework packages — like `urql` (for React), 20 + `@urql/preact`, `@urql/svelte`, and `@urql/vue` — wrap the [core package, 21 + `@urql/core`](./basics/core.md), which we can imagine as the brain 22 + of `urql` with most of its logic. As we progress with implementing `urql` into our application, 23 + we're later able to extend it by adding ["addon packages", which we call 24 + _Exchanges_](./concepts/exchanges.md) 28 25 29 - ## Quick Start 26 + If at this point you're still unsure of whether to use `urql`, [have a look at the **Comparison** 27 + page](./comparison.md) and check whether `urql` supports all features you're looking for. 30 28 31 - We have **Getting Started** guides for 32 - [React & 33 - Preact](https://formidable.com/open-source/urql/docs/basics/getting-started/#react--preact), 34 - [Svelte](https://formidable.com/open-source/urql/docs/basics/getting-started/#svelte), and 35 - [Vue](https://formidable.com/open-source/urql/docs/basics/getting-started/#vue) which walk through 36 - how to install the bindings for your framework of choice and set up the 37 - [`Client`](./api/core.md#client). 29 + ## Where to start 38 30 39 - Generally for React this would look like this, where the `urql` package may be replaced with your 40 - framework's bindings: 31 + We have **Getting Started** guides for: 41 32 42 - ```sh 43 - npm i --save urql graphql 44 - # or 45 - yarn add urql graphql 46 - ``` 33 + - [**React/Preact**](./basics/react-preact.md) covers how to work with the bindings for React/Preact. 34 + - [**Vue**](./basics/vue.md) covers how to work with the bindings for Vue 3. 35 + - [**Svelte**](./basics/svelte.md) covers how to work with the bindings for Svelte. 36 + - [**Core Package**](./basics/core.md) covers the shared "core APIs" and how we can use them directly 37 + in Node.js or imperatively. 47 38 48 - The **Basics** section also features pages to [write 49 - Queries](https://formidable.com/open-source/urql/docs/basics/queries/), 50 - [Mutations](https://formidable.com/open-source/urql/docs/basics/mutations/), after which we could 51 - continue learning about 52 - [Subscriptions](https://formidable.com/open-source/urql/docs/advanced/subscriptions/). These are 53 - among the only pages that are framework-specific. 39 + Each of these sections will walk you through the specific instructions for the framework bindings, 40 + including how to install and set them up, how to write queries, and how to send mutations. 54 41 55 - ## The Documentation 42 + ## Following the Documentation 56 43 57 44 This documentation is split into groups or sections that cover different levels of usage or areas of 58 45 interest. 59 46 60 - - **Basics** is the section where we find the ["Getting Started" 61 - guide](./basics/getting-started.md) and usage patterns for our framework of choice. 47 + - **Basics** is the section where we'll want to start learning about `urql` as it contains "Getting 48 + Started" guides for our framework of choice. 62 49 - **Main Concepts** then explains more about how `urql` functions, what it's made up of, and covers 63 50 the main aspects of the `Client` and GraphQL clients in general, on the ["Philosophy" 64 51 page](./concepts/philosophy.md). ··· 69 56 use-cases, smarter caching, and more dynamic apps to function. 70 57 - **Showcase** aims to list users of `urql`, third-party packages, and other helpful resources, 71 58 like tutorials and guides. 72 - - **API** contains a detailed list of all helpers, utilities, components, and other parts of each of 73 - `urql`'s packages, which may contain all details of each part and package. 59 + - **API** contains a detailed documentation on each package's APIs. The documentation links to each 60 + of these as appropriate, but if we're unsure of how to use a utility or package, we can go here 61 + directly to look up how to use a specific API. 74 62 75 63 We hope you grow to love `urql`!
+11 -17
docs/advanced/server-side-rendering.md
··· 252 252 `getStaticProps` and `getServerSideProps`. However we can enable this, let's look at an example: 253 253 254 254 ```js 255 - import { withUrqlClient, initUrqlClient } from "next-urql"; 256 - import { 257 - ssrExchange, 258 - dedupExchange, 259 - cacheExchange, 260 - fetchExchange, 261 - useQuery 262 - } from "urql"; 255 + import { withUrqlClient, initUrqlClient } from 'next-urql'; 256 + import { ssrExchange, dedupExchange, cacheExchange, fetchExchange, useQuery } from 'urql'; 263 257 264 258 const TODOS_QUERY = ` 265 259 query { todos { id text } } ··· 269 263 const [res] = useQuery({ query: TODOS_QUERY }); 270 264 return ( 271 265 <div> 272 - {res.data.todos.map((todo) => ( 266 + {res.data.todos.map(todo => ( 273 267 <div key={todo.id}> 274 268 {todo.id} - {todo.text} 275 269 </div> ··· 281 275 export async function getStaticProps(ctx) { 282 276 const ssrCache = ssrExchange({ isClient: false }); 283 277 const client = initUrqlClient({ 284 - url: "your-url", 285 - exchanges: [dedupExchange, cacheExchange, ssrCache, fetchExchange] 278 + url: 'your-url', 279 + exchanges: [dedupExchange, cacheExchange, ssrCache, fetchExchange], 286 280 }); 287 281 288 282 // This query is used to populate the cache for the query ··· 292 286 return { 293 287 props: { 294 288 // urqlState is a keyword here so withUrqlClient can pick it up. 295 - urqlState: ssrCache.extractData() 289 + urqlState: ssrCache.extractData(), 296 290 }, 297 - revalidate: 600 291 + revalidate: 600, 298 292 }; 299 293 } 300 294 301 295 export default withUrqlClient( 302 - (ssr) => ({ 303 - url: "your-url" 296 + ssr => ({ 297 + url: 'your-url', 304 298 }), 305 299 { ssr: false } // Important so we don't wrap our component in getInitialProps 306 300 )(Todos); ··· 326 320 loading. 327 321 328 322 We've previously seen how we can change our usage of `useQuery`'s `PromiseLike` result to [make use 329 - of Vue Suspense on the "Queries" page.](../basics/queries.md#vue-suspense) 323 + of Vue Suspense on the "Queries" page.](../basics/vue.md#vue-suspense) 330 324 331 325 Any component's `setup()` function can be updated to instead be an `async setup()` function, in 332 326 other words, to return a `Promise` instead of directly returning its data. This means that we can ··· 358 352 }); 359 353 360 354 const markup = await renderToString(app); 361 - 355 + 362 356 const data = JSON.stringify(ssr.extractData()); 363 357 364 358 res.status(200).send(`
+4 -4
docs/advanced/subscriptions.md
··· 5 5 6 6 # Subscriptions 7 7 8 - One feature of `urql` that was not mentioned in the ["Basics" section](../basics/README.md) is `urql`'s 8 + One feature of `urql` that was not mentioned in the ["Basics" sections](../basics/README.md) is `urql`'s 9 9 APIs and ability to handle GraphQL subscriptions. 10 10 11 11 ## The Subscription Exchange ··· 110 110 ## React & Preact 111 111 112 112 The `useSubscription` hooks comes with a similar API to `useQuery`, which [we've learned about in 113 - the "Queries" page in the "Basics" section.](../basics/queries.md#react--preact) 113 + the "Queries" page in the "Basics" section.](../basics/react-preact.md#queries) 114 114 115 115 Its usage is extremely similar in that it accepts options, which may contain `query` and 116 116 `variables`. However, it also accepts a second argument, which is a reducer function, similar to ··· 173 173 ## Svelte 174 174 175 175 The `subscription` function in `@urql/svelte` comes with a similar API to `query`, which [we've 176 - learned about in the "Queries" page in the "Basics" section.](../basics/queries.md#svelte) 176 + learned about in the "Queries" page in the "Basics" section.](../basics/svelte.md#queries) 177 177 178 178 Its usage is extremely similar in that it accepts an `operationStore`, which will typically contain 179 179 our GraphQL subscription query. However, `subscription` also accepts a second argument, which is ··· 231 231 ## Vue 232 232 233 233 The `useSubscription` API is very similar to `useQuery`, which [we've learned about in 234 - the "Queries" page in the "Basics" section.](../basics/queries.md#vue) 234 + the "Queries" page in the "Basics" section.](../basics/vue.md#queries) 235 235 236 236 Its usage is extremely similar in that it accepts options, which may contain `query` and 237 237 `variables`. However, it also accepts a second argument, which is a reducer function, similar to
+5 -4
docs/api/core.md
··· 1 - --- 1 + core.md--- 2 2 title: '@urql/core' 3 3 order: 0 4 + 4 5 --- 5 6 6 7 # @urql/core ··· 133 134 | `graphQLErrors` | `?Array<string \| GraphQLError>` | GraphQL Errors (if any) that were returned by the GraphQL API | 134 135 | `response` | `?any` | The raw response object (if any) from the `fetch` call | 135 136 136 - [Read more about errors in `urql` on the "Error" page.](../basics/errors.md) 137 + [Read more about errors in `urql` on the "Error" page.](../concepts/errors.md) 137 138 138 139 ## Types 139 140 ··· 193 194 - `'network-only'` 194 195 - `'cache-and-network'` 195 196 196 - [Read more about request policies on the "Queries" page.](../basics/queries.md#request-policies) 197 + [Read more about request policies on the "Document Caching" page.](../concepts/document-caching.md#request-policies) 197 198 198 199 ### OperationContext 199 200 ··· 267 268 268 269 ### cacheExchange 269 270 270 - The `cacheExchange` as [described on the "Document Caching" page.](../basics/document-caching.md). It's of type `Exchange`. 271 + The `cacheExchange` as [described on the "Document Caching" page.](../concepts/document-caching.md). It's of type `Exchange`. 271 272 272 273 ### subscriptionExchange 273 274
+1 -1
docs/api/request-policy-exchange.md
··· 9 9 that may be used to upgrade [Operations' Request Policies](./core.md#requestpolicy) on a 10 10 time-to-live basis. 11 11 12 - [Read more about request policies on the "Queries" page.](../basics/queries.md#request-policies) 12 + [Read more about request policies on the "Document Caching" page.](../concepts/document-caching.md#request-policies) 13 13 14 14 This exchange will conditionally upgrade `cache-first` and `cache-only` operations to use 15 15 `cache-and-network`, so that the client gets an opportunity to update its cached data, when the
+2 -2
docs/api/svelte.md
··· 56 56 57 57 This function will return the `operationStore` itself that has been passed. 58 58 59 - [Read more about how to use the `query` API on the "Queries" page.](../basics/queries.md#svelte) 59 + [Read more about how to use the `query` API on the "Queries" page.](../basics/svelte.md#queries) 60 60 61 61 ## subscription 62 62 ··· 94 94 mutation has been completed. 95 95 96 96 [Read more about how to use the `mutation` API on the "Mutations" 97 - page.](../basics/mutations.md#svelte) 97 + page.](../basics/svelte.md#mutations) 98 98 99 99 ## Context API 100 100
+10 -8
docs/api/urql.md
··· 27 27 it's called. When `pause` is set to `true` this executes the query, overriding the otherwise 28 28 paused hook. 29 29 30 - [Read more about how to use the `useQuery` API on the "Queries" page.](../basics/queries.md) 30 + [Read more about how to use the `useQuery` API on the "Queries" page.](../basics/react-preact.md#queries) 31 31 32 32 ## useMutation 33 33 ··· 40 40 [`Partial<OperationContext>`](./core.md#operationcontext) and may be used to start executing a 41 41 mutation. It returns a `Promise` resolving to an [`OperationResult`](./core.md#operationresult). 42 42 43 - [Read more about how to use the `useMutation` API on the "Mutations" page.](../basics/mutations.md) 43 + [Read more about how to use the `useMutation` API on the "Mutations" 44 + page.](../basics/react-preact.md#mutations) 44 45 45 46 ## useSubscription 46 47 47 48 Accepts a single required options object as an input with the following properties: 48 49 49 - | Prop | Type | Description | 50 - | ----------- | ------------------------ | ------------------------------------------------------------------------------------------- | 51 - | `query` | `string \| DocumentNode` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode. | 52 - | `variables` | `?object` | The variables to be used with the GraphQL request. | 53 - | `pause` | `?boolean` | A boolean flag instructing [execution to be paused](../basics/queries.md#pausing-usequery). | 54 - | `context` | `?object` | Holds the contextual information for the query. | 50 + | Prop | Type | Description | 51 + | ---------------------------------------------------- | ------------------------ | ---------------------------------------------------------------------------------- | 52 + | `query` | `string \| DocumentNode` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode. | 53 + | `variables` | `?object` | The variables to be used with the GraphQL request. | 54 + | `pause` | `?boolean` | A boolean flag instructing [execution to be | 55 + | paused](../basics/react-preact.md#pausing-usequery). | 56 + | `context` | `?object` | Holds the contextual information for the query. | 55 57 56 58 The hook optionally accepts a second argument, which may be a handler function with a type signature 57 59 of:
+9 -9
docs/api/vue.md
··· 14 14 | `query` | `string \| DocumentNode` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode. | 15 15 | `variables` | `?object` | The variables to be used with the GraphQL request. | 16 16 | `requestPolicy` | `?RequestPolicy` | An optional [request policy](./core.md#requestpolicy) that should be used specifying the cache strategy. | 17 - | `pause` | `?boolean` | A boolean flag instructing [execution to be paused](../basics/queries.md#pausing-usequery). | 17 + | `pause` | `?boolean` | A boolean flag instructing [execution to be paused](../basics/vue.md#pausing-usequery). | 18 18 | `pollInterval` | `?number` | Every `pollInterval` milliseconds the query will be reexecuted. | 19 19 | `context` | `?object` | Holds the contextual information for the query. | 20 20 ··· 43 43 When the promise is used, e.g. you `await useQuery(...)` then the `PromiseLike` will only resolve 44 44 once a result from the API is available. 45 45 46 - [Read more about how to use the `useQuery` API on the "Queries" page.](../basics/queries.md#vue) 46 + [Read more about how to use the `useQuery` API on the "Queries" page.](../basics/vue.md#queries) 47 47 48 48 ## useMutation 49 49 ··· 59 59 mutation. It returns a `Promise` resolving to an [`OperationResult`](./core.md#operationresult) 60 60 61 61 [Read more about how to use the `useMutation` API on the "Mutations" 62 - page.](../basics/mutations.md#vue) 62 + page.](../basics/vue.md#mutations) 63 63 64 64 ## useSubscription 65 65 66 66 Accepts a single required options object as an input with the following properties: 67 67 68 - | Prop | Type | Description | 69 - | ----------- | ------------------------ | ------------------------------------------------------------------------------------------- | 70 - | `query` | `string \| DocumentNode` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode. | 71 - | `variables` | `?object` | The variables to be used with the GraphQL request. | 72 - | `pause` | `?boolean` | A boolean flag instructing [execution to be paused](../basics/queries.md#pausing-usequery). | 73 - | `context` | `?object` | Holds the contextual information for the subscription. | 68 + | Prop | Type | Description | 69 + | ----------- | ------------------------ | --------------------------------------------------------------------------------------- | 70 + | `query` | `string \| DocumentNode` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode. | 71 + | `variables` | `?object` | The variables to be used with the GraphQL request. | 72 + | `pause` | `?boolean` | A boolean flag instructing [execution to be paused](../basics/vue.md#pausing-usequery). | 73 + | `context` | `?object` | Holds the contextual information for the subscription. | 74 74 75 75 Each of these inputs may also be [reactive](https://v3.vuejs.org/api/refs-api.html) (e.g. a `ref`) 76 76 and are allowed to change over time which will issue a new query.
+11 -8
docs/basics/README.md
··· 6 6 # Basics 7 7 8 8 In this chapter we'll explain the basics of `urql` and how to get started with using it without any 9 - prior knowledge. It's split into multiple pages that are best read in order. 9 + prior knowledge. 10 10 11 - - [**Getting started**](./getting-started.md) covers how to install the package for your framework of choice and set it up. 12 - - [**Queries**](./queries.md) explains how to write your first GraphQL queries with `urql`. 13 - - [**Mutations**](./mutations.md) follows up with how to define GraphQL mutations. 14 - - [**Document Caching**](./document-caching.md) explains the default cache mechanism of `urql`, as opposed to the opt-in 15 - [Normalized Cache](../graphcache/normalized-caching.md). 16 - - [**Errors**](./errors.md) contains information on error handling in `urql`. 11 + - [**React/Preact**](./react-preact.md) covers how to work with the bindings for React/Preact. 12 + - [**Vue**](./vue.md) covers how to work with the bindings for Vue 3. 13 + - [**Svelte**](./svelte.md) covers how to work with the bindings for Svelte. 14 + - [**Core Package**](./core-package.md) defines why a shared package exists that contains the main 15 + logic of `urql`, and how we can use it directly in Node.js. 17 16 18 17 After reading "Basics" you may want to [read the "Concepts" chapter of the 19 18 documentation](../concepts/README.md) as it explains the motivation and architecture that drives 20 - `urql`. 19 + `urql`. Two notable sections there include: 20 + 21 + - [**Document Caching**](../concepts/document-caching.md) explains the default cache mechanism of `urql`, as opposed to the opt-in 22 + [Normalized Cache](../graphcache/normalized-caching.md). 23 + - [**Errors**](../concepts/errors.md) contains information on error handling in `urql`.
+166
docs/basics/core.md
··· 1 + --- 2 + title: Core 3 + order: 3 4 + --- 5 + 6 + # Core 7 + 8 + The `@urql/core` package contains `urql`'s `Client`, some common utilities, and some default 9 + _Exchanges_. These are the shared, default parts of `urql` that we will be using no matter which 10 + framework we're interacting with. 11 + 12 + All framework bindings — meaning `urql`, `@urql/preact`, `@urql/svelte`, and `@urql/vue` — reexport 13 + all exports of our `@urql/core` core library. This means that if we want to use `urql`'s `Client` 14 + imperatively or with Node.js we'd use `@urql/core`'s utilities or the `Client` directly. 15 + 16 + ## Getting started 17 + 18 + Installing `@urql/core` is quick and no other packages are immediately necessary. 19 + 20 + ```sh 21 + yarn add @urql/core graphql 22 + # or 23 + npm install --save @urql/core graphql 24 + ``` 25 + 26 + ### One-off Queries and Mutations 27 + 28 + When you're using `urql` to send one-off queries or mutations — rather than in full framework code, 29 + where updates are important — it's common to convert the streams that we get to promises. The 30 + `client.query` and `client.mutation` methods have a shortcut to do just that. 31 + 32 + ```js 33 + const QUERY = ` 34 + query Test($id: ID!) { 35 + getUser(id: $id) { 36 + id 37 + name 38 + } 39 + } 40 + `; 41 + 42 + client 43 + .query(QUERY, { id: 'test' }) 44 + .toPromise() 45 + .then(result => { 46 + console.log(result); // { data: ... } 47 + }); 48 + ``` 49 + 50 + This may be useful when we don't plan on cancelling queries or we don't care about future updates to 51 + this data and are just looking to query a result once. 52 + 53 + Similarly there's a way to read data from the cache synchronously, provided that the cache has 54 + received a result for a given query before. The `Client` has a `readQuery` method which is a 55 + shortcut for just that. 56 + 57 + ```js 58 + const QUERY = ` 59 + query Test($id: ID!) { 60 + getUser(id: $id) { 61 + id 62 + name 63 + } 64 + } 65 + `; 66 + 67 + const result = client.readQuery(QUERY, { id: 'test' }); 68 + 69 + result; // null or { data: ... } 70 + ``` 71 + 72 + Since the streams in `urql` operate synchronously, internally this method subscribes to 73 + `client.executeQuery` and unsubscribes immediately. If a result is available in the cache it will be 74 + resolved synchronously prior to the unsubscribe. If not, the query is cancelled and no request will be sent to the GraphQL API. 75 + 76 + ### gql 77 + 78 + A notable utility function is the `gql` tagged template literal function, which is a drop-in 79 + replacement for `graphql-tag`, if you're coming from other GraphQL clients. 80 + 81 + Wherever `urql` accepts a query document, you may either pass a string or a `DocumentNode`. `gql` is 82 + a utility that allows a `DocumentNode` to be created directly, and others to be interpolated into 83 + it, which is useful for fragments for instance. This function will often also mark GraphQL documents 84 + for syntax highlighting in most code editors. 85 + 86 + In most examples we may have passed a string to define a query document, like so: 87 + 88 + ```js 89 + const TodosQuery = ` 90 + query { 91 + todos { 92 + id 93 + title 94 + } 95 + } 96 + `; 97 + ``` 98 + 99 + We may also use the `gql` tag function to create a `DocumentNode` directly: 100 + 101 + ```js 102 + import { gql } from '@urql/core'; 103 + 104 + const TodosQuery = gql` 105 + query { 106 + todos { 107 + id 108 + title 109 + } 110 + } 111 + `; 112 + ``` 113 + 114 + Since all framework bindings also re-export `@urql/core`, we may also import `gql` from `'urql'`, 115 + `'@urql/svelte'` and other bindings directly. 116 + 117 + We can also start interpolating other documents into the tag function. This is useful to compose 118 + fragment documents into a larger query, since it's common to define fragments across components of 119 + an app to spread out data dependencies. If we accidentally use a duplicate fragment name in a 120 + document, `gql` will log a warning, since GraphQL APIs won't accept duplicate names. 121 + 122 + ```js 123 + import { gql } from '@urql/core'; 124 + 125 + const TodoFragment = gql` 126 + fragment SmallTodo on Todo { 127 + id 128 + title 129 + } 130 + `; 131 + 132 + const TodosQuery = gql` 133 + query { 134 + todos { 135 + ...TodoFragment 136 + } 137 + } 138 + 139 + ${TodoFragment} 140 + `; 141 + ``` 142 + 143 + ## Common Utilities in Core 144 + 145 + The `@urql/core` package contains other utilities that are shared between multiple addon packages. 146 + This is a short but non-exhaustive list. It contains, 147 + 148 + - [`CombinedError`](../api/core.md#combinederror) - our abstraction to combine one or more `GraphQLError`(s) and a `NetworkError` 149 + - `makeResult` and `makeErrorResult` - utilities to create _Operation Results_ 150 + - [`createRequest`](../api/core.md#createrequest) - a utility function to create a request from a query and some variables (which 151 + generates a stable _Operation Key_) 152 + 153 + There are other utilities not mentioned here. Read more about the `@urql/core` API in the [API docs](../api/core.md). 154 + 155 + ## Reading on 156 + 157 + This concludes the introduction for using `@urql/core` without any framework bindings. This showed 158 + just a couple of ways to use `gql` or the `Client`, however you may also want to learn more about 159 + [how to use `urql`'s streams](../concepts/stream-patterns.md). Furthermore, apart from the framework 160 + binding introductions, there are some other pages that provide more information on how to get fully 161 + set up with `urql`: 162 + 163 + - [How does the default "document cache" work?](../concepts/document-caching.md) 164 + - [How are errors handled and represented?](../concepts/errors.md) 165 + - [A quick overview of `urql`'s philosophy and structure.](../concepts/philosophy.md) 166 + - [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
+18 -5
docs/basics/document-caching.md docs/concepts/document-caching.md
··· 1 1 --- 2 2 title: Document Caching 3 - order: 3 3 + order: 1 4 4 --- 5 5 6 6 # Document Caching ··· 39 39 40 40 ## Request Policies 41 41 42 - [We previously covered request policies on the "Queries" page.](./queries.md) 42 + The _request policy_ that is defined will alter what the default document cache does. By default the 43 + cache will prefer cached results and will otherwise send a request, which is called `cache-first`. 44 + In total there are four different policies that we can use: 45 + 46 + - `cache-first` (the default) prefers cached results and falls back to sending an API request when 47 + no prior result is cached. 48 + - `cache-and-network` returns cached results but also always sends an API request, which is perfect 49 + for displaying data quickly while keeping it up-to-date. 50 + - `network-only` will always send an API request and will ignore cached results. 51 + - `cache-only` will always return cached results or `null`. 52 + 53 + The `cache-and-network` policy is particularly useful, since it allows us to display data instantly 54 + if it has been cached, but also refreshes data in our cache in the background. This means though 55 + that `fetching` will be `false` for cached results although an API request may still be ongoing in 56 + the background. 43 57 44 - The _request policy_ that is defined will alter what the default document cache does. By default the 45 - cache will prefer cached results and will otherwise send a request, which is called `cache-first`, 46 - but there's also `cache-and-network`, `cache-only`, and `network-only`. 58 + For this reason there's another field on results, `result.stale`, which indicates that the cached 59 + result is either outdated or that another request is being sent in the background. 47 60 48 61 [Read more about which request policies are available in the API 49 62 docs.](../api/core.md#requestpolicy-type)
+1 -1
docs/basics/errors.md docs/concepts/errors.md
··· 1 1 --- 2 2 title: Errors 3 - order: 4 3 + order: 2 4 4 --- 5 5 6 6 # Error handling
-306
docs/basics/getting-started.md
··· 1 - --- 2 - title: Getting started 3 - order: 0 4 - --- 5 - 6 - # Getting started 7 - 8 - In the ["Introduction"](./README.md) we read how `urql` consists of multiple constituent parts that 9 - make up a GraphQL client. Hence there are multiple packages — one for each framework we officially 10 - support — that we'll get started with on this page. 11 - 12 - ## React & Preact 13 - 14 - This "Getting Started" guide covers how to install and set up `urql` and the `Client`, for React and 15 - Preact. Since the `urql` and `@urql/preact` packages share most of their API and are used in the 16 - same way, when reading the documentation on React, all examples are essentially the same, except 17 - that we'd want to use the `@urql/preact` package instead of the `urql` package for Preact. 18 - 19 - ### Installation 20 - 21 - Installing `urql` is as quick as you'd expect and you won't need any other packages to get started 22 - with at first. We'll install the package with our package manager of choice. 23 - 24 - ```sh 25 - yarn add urql graphql 26 - # or 27 - npm install --save urql graphql 28 - ``` 29 - 30 - To use `urql` with Preact, we have to install `@urql/preact` instead of `urql` and import from 31 - that package instead. Otherwise all examples for Preact will be the same. 32 - 33 - Most libraries related to GraphQL also need the `graphql` package to be installed as a peer 34 - dependency, so that they can adapt to your specific versioning requirements. That's why we'll need 35 - to install `graphql` alongside `urql`. 36 - 37 - Both the `urql` and `graphql` packages follow [semantic versioning](https://semver.org) and all 38 - `urql` packages will define a range of compatible versions of `graphql`. Watch out for breaking 39 - changes in the future however, in which case your package manager may warn you about `graphql` being 40 - out of the defined peer dependency range. 41 - 42 - ### Setting up the `Client` 43 - 44 - The `urql` and `@urql/preact` packages export a method called `createClient` which we can use to 45 - create the GraphQL client. This central `Client` manages all of our GraphQL requests and results. 46 - 47 - ```js 48 - import { createClient } from 'urql'; 49 - 50 - const client = createClient({ 51 - url: 'http://localhost:3000/graphql', 52 - }); 53 - ``` 54 - 55 - At the bare minimum we'll need to pass an API's `url` when we create a `Client` to get started. 56 - 57 - Another common option is `fetchOptions`. This option allows us to customize the options that will be 58 - passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or 59 - a function returning an options object. 60 - 61 - In the following example we'll add a token to each `fetch` request that our `Client` sends to our 62 - GraphQL API. 63 - 64 - ```js 65 - const client = createClient({ 66 - url: 'http://localhost:3000/graphql', 67 - fetchOptions: () => { 68 - const token = getToken(); 69 - return { 70 - headers: { authorization: token ? `Bearer ${token}` : '' }, 71 - }; 72 - }, 73 - }); 74 - ``` 75 - 76 - ### Providing the `Client` 77 - 78 - To make use of the `Client` in React & Preact we will have to provide it via the 79 - [Context API](https://reactjs.org/docs/context.html). This may be done with the help of 80 - the `Provider` export. 81 - 82 - ```jsx 83 - import { createClient, Provider } from 'urql'; 84 - 85 - const client = createClient({ 86 - url: 'http://localhost:3000/graphql', 87 - }); 88 - 89 - const App = () => ( 90 - <Provider value={client}> 91 - <YourRoutes /> 92 - </Provider> 93 - ); 94 - ``` 95 - 96 - Now every component and element inside and under the `Provider` are able to use GraphQL queries that 97 - will be sent to our API. 98 - 99 - [On the next page we'll learn about executing "Queries".](./queries.md#react--preact) 100 - 101 - ## Svelte 102 - 103 - This "Getting Started" guide covers how to install and set up `urql` and provide a `Client` for 104 - Svelte. The `@urql/svelte` package, which provides bindings for Svelte, doesn't fundamentally 105 - function differently from `@urql/preact` or `urql` and uses the same [Core Package and 106 - `Client`](../concepts/core-package.md). 107 - 108 - ### Installation 109 - 110 - Installing `@urql/svelte` is quick and no other packages are immediately necessary. 111 - 112 - ```sh 113 - yarn add @urql/svelte graphql 114 - # or 115 - npm install --save @urql/svelte graphql 116 - ``` 117 - 118 - Most libraries related to GraphQL also need the `graphql` package to be installed as a peer 119 - dependency, so that they can adapt to your specific versioning requirements. That's why we'll need 120 - to install `graphql` alongside `@urql/svelte`. 121 - 122 - Both the `@urql/svelte` and `graphql` packages follow [semantic versioning](https://semver.org) and 123 - all `@urql/svelte` packages will define a range of compatible versions of `graphql`. Watch out 124 - for breaking changes in the future however, in which case your package manager may warn you about 125 - `graphql` being out of the defined peer dependency range. 126 - 127 - ### Setting up the `Client` 128 - 129 - The `@urql/svelte` package exports a method called `createClient` which we can use to create 130 - the GraphQL client. This central `Client` manages all of our GraphQL requests and results. 131 - 132 - ```js 133 - import { createClient } from '@urql/svelte'; 134 - 135 - const client = createClient({ 136 - url: 'http://localhost:3000/graphql', 137 - }); 138 - ``` 139 - 140 - At the bare minimum we'll need to pass an API's `url` when we create a `Client` to get started. 141 - 142 - Another common option is `fetchOptions`. This option allows us to customize the options that will be 143 - passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or 144 - a function returning an options object. 145 - 146 - In the following example we'll add a token to each `fetch` request that our `Client` sends to our 147 - GraphQL API. 148 - 149 - ```js 150 - const client = createClient({ 151 - url: 'http://localhost:3000/graphql', 152 - fetchOptions: () => { 153 - const token = getToken(); 154 - return { 155 - headers: { authorization: token ? `Bearer ${token}` : '' }, 156 - }; 157 - }, 158 - }); 159 - ``` 160 - 161 - ### Providing the `Client` 162 - 163 - To make use of the `Client` in Svelte we will have to provide it via the 164 - [Context API](https://svelte.dev/tutorial/context-api). From a parent component to its child 165 - components. This will share one `Client` with the rest of our app, if we for instance provide the 166 - `Client` 167 - 168 - ```html 169 - <script> 170 - import { createClient, setClient } from '@urql/svelte'; 171 - 172 - const client = createClient({ 173 - url: 'http://localhost:3000/graphql', 174 - }); 175 - 176 - setClient(client); 177 - </script> 178 - ``` 179 - 180 - The `setClient` method internally calls [Svelte's `setContext` 181 - function](https://svelte.dev/docs#setContext). The `@urql/svelte` package also exposes a `getClient` 182 - function that uses [`getContext`](https://svelte.dev/docs#getContext) to retrieve the `Client` in 183 - child components. This is used throughout `@urql/svelte`'s API. 184 - 185 - We can also use a convenience function, `initClient`. This function combines the `createClient` and 186 - `setClient` calls into one. 187 - 188 - ```html 189 - <script> 190 - import { initClient } from '@urql/svelte'; 191 - 192 - initClient({ 193 - url: 'http://localhost:3000/graphql', 194 - }); 195 - </script> 196 - ``` 197 - 198 - [On the next page we'll learn about executing "Queries".](./queries.md#svelte) 199 - 200 - ## Vue 201 - 202 - This "Getting Started" guide covers how to install and set up `urql` and provide a `Client` for 203 - Vue. The `@urql/vue` package, which provides bindings for Vue, doesn't fundamentally 204 - function differently from `@urql/preact`, or `urql` and uses the same [Core Package and 205 - `Client`](../concepts/core-package.md). 206 - 207 - The `@urql/vue` bindings have been written with [Vue 208 - 3](https://github.com/vuejs/vue-next/releases/tag/v3.0.0) in mind and use Vue's newer [Composition 209 - API](https://v3.vuejs.org/guide/composition-api-introduction.html). This gives the `@urql/vue` 210 - bindings capabilities to be more easily integrated into your existing `setup()` functions. 211 - 212 - ### Installation 213 - 214 - Installing `@urql/vue` is quick and no other packages are immediately necessary. 215 - 216 - ```sh 217 - yarn add @urql/vue graphql 218 - # or 219 - npm install --save @urql/vue graphql 220 - ``` 221 - 222 - Most libraries related to GraphQL also need the `graphql` package to be installed as a peer 223 - dependency, so that they can adapt to your specific versioning requirements. That's why we'll need 224 - to install `graphql` alongside `@urql/vue`. 225 - 226 - Both the `@urql/vue` and `graphql` packages follow [semantic versioning](https://semver.org) and 227 - all `@urql/vue` packages will define a range of compatible versions of `graphql`. Watch out 228 - for breaking changes in the future however, in which case your package manager may warn you about 229 - `graphql` being out of the defined peer dependency range. 230 - 231 - ### Setting up the `Client` 232 - 233 - The `@urql/vue` package exports a method called `createClient` which we can use to create 234 - the GraphQL client. This central `Client` manages all of our GraphQL requests and results. 235 - 236 - ```js 237 - import { createClient } from '@urql/vue'; 238 - 239 - const client = createClient({ 240 - url: 'http://localhost:3000/graphql', 241 - }); 242 - ``` 243 - 244 - At the bare minimum we'll need to pass an API's `url` when we create a `Client` to get started. 245 - 246 - Another common option is `fetchOptions`. This option allows us to customize the options that will be 247 - passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or 248 - a function returning an options object. 249 - 250 - In the following example we'll add a token to each `fetch` request that our `Client` sends to our 251 - GraphQL API. 252 - 253 - ```js 254 - const client = createClient({ 255 - url: 'http://localhost:3000/graphql', 256 - fetchOptions: () => { 257 - const token = getToken(); 258 - return { 259 - headers: { authorization: token ? `Bearer ${token}` : '' }, 260 - }; 261 - }, 262 - }); 263 - ``` 264 - 265 - ### Providing the `Client` 266 - 267 - To make use of the `Client` in Vue we will have to provide from a parent component to its child 268 - components. This will share one `Client` with the rest of our app. In `@urql/vue` there are two 269 - different ways to achieve this. 270 - 271 - The first method is to use `@urql/vue`'s `provideClient` function. This must be called in any of 272 - your parent components and accepts either a `Client` directly or just the options that you'd pass to 273 - `createClient`. 274 - 275 - ```html 276 - <script> 277 - import { createClient, provideClient } from '@urql/vue'; 278 - 279 - const client = createClient({ 280 - url: 'http://localhost:3000/graphql', 281 - }); 282 - 283 - provideClient(client); 284 - </script> 285 - ``` 286 - 287 - Alternatively we may use the exported `install` function and treat `@urql/vue` as a plugin by 288 - importing its default export and using it [as a plugin](https://v3.vuejs.org/guide/plugins.html#using-a-plugin). 289 - 290 - ```js 291 - import { createApp } from 'vue'; 292 - import Root from './App.vue'; 293 - import urql from '@urql/vue'; 294 - 295 - const app = createApp(Root); 296 - 297 - app.use(urql, { 298 - url: 'http://localhost:3000/graphql', 299 - }); 300 - 301 - app.mount('#app'); 302 - ``` 303 - 304 - The plugin also accepts `createClient`'s options or a `Client` as its inputs. 305 - 306 - [On the next page we'll learn about executing "Queries".](./queries.md#vue)
-349
docs/basics/mutations.md
··· 1 - --- 2 - title: Mutations 3 - order: 2 4 - --- 5 - 6 - # Mutations 7 - 8 - In this chapter we'll learn how to execute mutations and view their results. 9 - Sending mutations to our GraphQL API is similar to what we've learned about sending queries to our 10 - API [previously on the "Queries" page.](./queries.md) 11 - 12 - ## React & Preact 13 - 14 - This guide covers how to send mutations in React and Preact, which share almost the same API. 15 - 16 - Both libraries offer a `useMutation` hook and a `Mutation` component. The latter accepts the same 17 - parameters but we won't cover it in this guide. [Look it up in the API docs if you prefer 18 - render-props components.](../api/urql.md#mutation-component) 19 - 20 - ### Sending a mutation 21 - 22 - Let's again pick up an example with an imaginary GraphQL API for todo items, and dive into an 23 - example! We'll set up a mutation that _updates_ a todo item's title. 24 - 25 - ```jsx 26 - const UpdateTodo = ` 27 - mutation ($id: ID!, $title: String!) { 28 - updateTodo (id: $id, title: $title) { 29 - id 30 - title 31 - } 32 - } 33 - `; 34 - 35 - const Todo = ({ id, title }) => { 36 - const [updateTodoResult, updateTodo] = useMutation(UpdateTodo); 37 - }; 38 - ``` 39 - 40 - Similar to the `useQuery` output, `useMutation` returns a tuple. The first item in the tuple again 41 - contains `fetching`, `error`, and `data` — it's identical since this is a common pattern of how 42 - `urql` presents [operation results](../api/core.md#operationresult). 43 - 44 - Unlike the `useQuery` hook, the `useMutation` hook doesn't execute automatically. At this point in 45 - our example, no mutation will be performed. To execute our mutation we instead have to call the 46 - execute function — `updateTodo` in our example — which is the second item in the tuple. 47 - 48 - ### Using the mutation result 49 - 50 - When calling our `updateTodo` function we have two ways of getting to the result as it comes back 51 - from our API. We can either use the first value of the returned tuple — our `updateTodoResult` — or 52 - we can use the promise that `updateTodo` returns. 53 - 54 - ```jsx 55 - const Todo = ({ id, title }) => { 56 - const [updateTodoResult, updateTodo] = useMutation(UpdateTodo); 57 - 58 - const submit = newTitle => { 59 - const variables = { id, title: newTitle || '' }; 60 - updateTodo(variables).then(result => { 61 - // The result is almost identical to `updateTodoResult` with the exception 62 - // of `result.fetching` not being set. 63 - // It is an OperationResult. 64 - }); 65 - }; 66 - }; 67 - ``` 68 - 69 - The result is useful when your UI has to display progress on the mutation, and the returned 70 - promise is particularly useful when you're adding side-effects that run after the mutation has 71 - completed. 72 - 73 - ### Handling mutation errors 74 - 75 - It's worth noting that the promise we receive when calling the execute function will never 76 - reject. Instead it will always return a promise that resolves to a result. 77 - 78 - If you're checking for errors, you should use `result.error` instead, which will be set 79 - to a `CombinedError` when any kind of errors occurred while executing your mutation. 80 - [Read more about errors on our "Errors" page.](./errors.md) 81 - 82 - ```jsx 83 - const Todo = ({ id, title }) => { 84 - const [updateTodoResult, updateTodo] = useMutation(UpdateTodo); 85 - 86 - const submit = newTitle => { 87 - const variables = { id, title: newTitle || '' }; 88 - updateTodo(variables).then(result => { 89 - if (result.error) { 90 - console.error('Oh no!', result.error); 91 - } 92 - }); 93 - }; 94 - }; 95 - ``` 96 - 97 - There are some more tricks we can use with `useMutation`.<br /> 98 - [Read more about its API in the API docs for it.](../api/urql.md#usemutation) 99 - 100 - [On the next page we'll learn about "Document Caching", `urql`'s default caching 101 - mechanism.](./document-caching.md) 102 - 103 - ## Svelte 104 - 105 - This guide covers how to send mutations in Svelte using `@urql/svelte`'s `mutation` utility. 106 - The `mutation` function isn't dissimilar from the `query` function but is triggered manually and 107 - can accept a [`GraphQLRequest` object](../api/core.md#graphqlrequest) too while also supporting our 108 - trusty `operationStore`. 109 - 110 - ### Sending a mutation 111 - 112 - Let's again pick up an example with an imaginary GraphQL API for todo items, and dive into an 113 - example! We'll set up a mutation that _updates_ a todo item's title. 114 - 115 - ```html 116 - <script> 117 - import { mutation } from '@urql/svelte'; 118 - 119 - export let id; 120 - 121 - const mutateTodo = mutation({ 122 - query: ` 123 - mutation ($id: ID!, $title: String!) { 124 - updateTodo (id: $id, title: $title) { 125 - id 126 - title 127 - } 128 - } 129 - `, 130 - }); 131 - 132 - function updateTodo(newTitle) { 133 - mutateTodo({ id, title: newTitle }); 134 - } 135 - </script> 136 - ``` 137 - 138 - This small call to `mutation` accepts a `query` property (besides the `variables` property) and 139 - returns an execute function. We've wrapped it in an `updateTodo` function to illustrate its usage. 140 - 141 - Unlike the `query` function, the `mutation` function doesn't start our mutation automatically. 142 - Instead, mutations are started programmatically by calling the function they return. This function 143 - also returns a promise so that we can use the mutation's result. 144 - 145 - ### Using the mutation result 146 - 147 - When calling `mutateTodo` in our previous example, we start the mutation. To use the mutation's 148 - result we actually have two options instead of one. 149 - 150 - The first option is to use the promise that the `mutation`'s execute function returns. This promise 151 - will resolve to an `operationStore`, which is what we're used to from sending queries. Using this 152 - store we can then read the mutation's `data` or `error`. 153 - 154 - ```html 155 - <script> 156 - import { mutation } from '@urql/svelte'; 157 - 158 - export let id; 159 - 160 - const mutateTodo = mutation({ 161 - query: ` 162 - mutation ($id: ID!, $title: String!) { 163 - updateTodo (id: $id, title: $title) { 164 - id 165 - title 166 - } 167 - } 168 - `, 169 - }); 170 - 171 - function updateTodo(newTitle) { 172 - mutateTodo({ id, title: newTitle }).then(result => { 173 - // The result is an operationStore again, which will already carry the mutation's result 174 - console.log(result.data, result.error); 175 - }); 176 - } 177 - </script> 178 - ``` 179 - 180 - Alternatively, we can pass `mutation` an `operationStore` directly. This allows us to use a 181 - mutation's result in our component's UI more easily, without storing it ourselves. 182 - 183 - ```html 184 - <script> 185 - import { operationStore, mutation } from '@urql/svelte'; 186 - 187 - export let id; 188 - 189 - const updateTodoStore = operationStore(` 190 - mutation ($id: ID!, $title: String!) { 191 - updateTodo (id: $id, title: $title) { 192 - id 193 - title 194 - } 195 - } 196 - `); 197 - 198 - const updateTodoMutation = mutation(updateTodoStore); 199 - 200 - function updateTodo(newTitle) { 201 - updateTodoMutation({ id, title: newTitle }); 202 - } 203 - </script> 204 - 205 - {#if $updateTodoStore.data} Todo was updated! {/if} 206 - ``` 207 - 208 - ### Handling mutation errors 209 - 210 - It's worth noting that the promise we receive when calling the execute function will never 211 - reject. Instead it will always return a promise that resolves to an `operationStore`, even if the 212 - mutation has failed. 213 - 214 - If you're checking for errors, you should use `operationStore.error` instead, which will be set 215 - to a `CombinedError` when any kind of errors occurred while executing your mutation. 216 - [Read more about errors on our "Errors" page.](./errors.md) 217 - 218 - ```jsx 219 - mutateTodo({ id, title: newTitle }).then(result => { 220 - if (result.error) { 221 - console.error('Oh no!', result.error); 222 - } 223 - }); 224 - ``` 225 - 226 - [On the next page we'll learn about "Document Caching", `urql`'s default caching 227 - mechanism.](./document-caching.md) 228 - 229 - ## Vue 230 - 231 - This guide covers how to send mutations in Vue using `@urql/vue`'s `useMutation` API. 232 - The `useMutation` function isn't dissimilar from `useQuery` but is triggered manually and accepts 233 - only a `DocumentNode` or `string` as an input. 234 - 235 - ### Sending a mutation 236 - 237 - Let's again pick up an example with an imaginary GraphQL API for todo items, and dive into an 238 - example! We'll set up a mutation that _updates_ a todo item's title. 239 - 240 - ```js 241 - import { useMutation } from '@urql/vue'; 242 - 243 - export default { 244 - setup() { 245 - const { executeMutation: updateTodo } = useMutation(` 246 - mutation ($id: ID!, $title: String!) { 247 - updateTodo (id: $id, title: $title) { 248 - id 249 - title 250 - } 251 - } 252 - `); 253 - 254 - return { updateTodo }; 255 - }, 256 - }; 257 - ``` 258 - 259 - Similar to the `useQuery` output, `useMutation` returns a result object, which reflects the data of 260 - an executed mutation. That means it'll contain the familiar `fetching`, `error`, and `data` 261 - properties — it's identical since this is a common pattern of how `urql` 262 - presents [operation results](../api/core.md#operationresult). 263 - 264 - Unlike the `useQuery` hook, the `useMutation` hook doesn't execute automatically. At this point in 265 - our example, no mutation will be performed. To execute our mutation we instead have to call the 266 - `executeMutation` method on the result with some variables. 267 - 268 - ### Using the mutation result 269 - 270 - When calling our `updateTodo` function we have two ways of getting to the result as it comes back 271 - from our API. We can either use the result itself, since all properties related to the last 272 - [operation result](../api/core.md#operationresult) are marked as [reactive 273 - ](https://v3.vuejs.org/guide/reactivity-fundamentals.html) — or we can use the promise that the 274 - `executeMutation` method returns when it's called: 275 - 276 - ```js 277 - import { useMutation } from '@urql/vue'; 278 - 279 - export default { 280 - setup() { 281 - const updateTodoResult = useMutation(` 282 - mutation ($id: ID!, $title: String!) { 283 - updateTodo (id: $id, title: $title) { 284 - id 285 - title 286 - } 287 - } 288 - `); 289 - 290 - return { 291 - updateTodo(id, title) { 292 - const variables = { id, title: title || '' }; 293 - updateTodoResult(variables).then(result => { 294 - // The result is almost identical to `updateTodoResult` with the exception 295 - // of `result.fetching` not being set and its properties not being reactive. 296 - // It is an OperationResult. 297 - }); 298 - }, 299 - }; 300 - }, 301 - }; 302 - ``` 303 - 304 - The reactive result that `useMutation` returns is useful when your UI has to display progress or 305 - results on the mutation, and the returned promise is particularly useful when you're adding 306 - side-effects that run after the mutation has completed. 307 - 308 - ### Handling mutation errors 309 - 310 - It's worth noting that the promise we receive when calling the execute function will never 311 - reject. Instead it will always return a promise that resolves to a result. 312 - 313 - If you're checking for errors, you should use `result.error` instead, which will be set 314 - to a `CombinedError` when any kind of errors occurred while executing your mutation. 315 - [Read more about errors on our "Errors" page.](./errors.md) 316 - 317 - ```js 318 - import { useMutation } from '@urql/vue'; 319 - 320 - export default { 321 - setup() { 322 - const updateTodoResult = useMutation(` 323 - mutation ($id: ID!, $title: String!) { 324 - updateTodo (id: $id, title: $title) { 325 - id 326 - title 327 - } 328 - } 329 - `); 330 - 331 - return { 332 - updateTodo(id, title) { 333 - const variables = { id, title: title || '' }; 334 - updateTodoResult(variables).then(result => { 335 - if (result.error) { 336 - console.error('Oh no!', result.error); 337 - } 338 - }); 339 - }, 340 - }; 341 - }, 342 - }; 343 - ``` 344 - 345 - There are some more tricks we can use with `useMutation`.<br /> 346 - [Read more about its API in the API docs for it.](../api/vue.md#usemutation) 347 - 348 - [On the next page we'll learn about "Document Caching", `urql`'s default caching 349 - mechanism.](./document-caching.md)
-901
docs/basics/queries.md
··· 1 - --- 2 - title: Queries 3 - order: 1 4 - --- 5 - 6 - # Queries 7 - 8 - Let's get to querying our data! This page will teach us how we can retrieve our data declaratively 9 - from our GraphQL API with the help of `urql`. 10 - 11 - ## React & Preact 12 - 13 - This guide covers how to query data with React and Preact, which share almost the same API. 14 - 15 - Both libraries offer a `useQuery` hook and a `Query` component. The latter accepts the same 16 - parameters but we won't cover it in this guide. [Look it up in the API docs if you prefer 17 - render-props components.](../api/urql.md#query-component) 18 - 19 - ### Run a first query 20 - 21 - For the following examples, we'll imagine that we're querying data from a GraphQL API that contains 22 - todo items. Let's dive right into it! 23 - 24 - ```jsx 25 - import { useQuery } from 'urql'; 26 - 27 - const TodosQuery = ` 28 - query { 29 - todos { 30 - id 31 - title 32 - } 33 - } 34 - `; 35 - 36 - const Todos = () => { 37 - const [result, reexecuteQuery] = useQuery({ 38 - query: TodosQuery, 39 - }); 40 - 41 - const { data, fetching, error } = result; 42 - 43 - if (fetching) return <p>Loading...</p>; 44 - if (error) return <p>Oh no... {error.message}</p>; 45 - 46 - return ( 47 - <ul> 48 - {data.todos.map(todo => ( 49 - <li key={todo.id}>{todo.title}</li> 50 - ))} 51 - </ul> 52 - ); 53 - }; 54 - ``` 55 - 56 - Here we have implemented our first GraphQL query to fetch todos. We see that `useQuery` accepts 57 - options and returns a tuple. In this case we've set the `query` option to our GraphQL query. The 58 - tuple we then get in return is an array that contains a result object and a re-execute function. 59 - 60 - The result object contains several properties. The `fetching` field indicates whether we're currently 61 - loading data, `data` contains the actual `data` from the API's result, and `error` is set when either 62 - the request to the API has failed or when our API result contained some `GraphQLError`s, which 63 - we'll get into later on the ["Errors" page](./errors.md). 64 - 65 - ### Variables 66 - 67 - Typically we'll also need to pass variables to our queries, for instance, if we are dealing with 68 - pagination. For this purpose the `useQuery` hook also accepts a `variables` option, which we can use 69 - to supply variables to our query. 70 - 71 - ```jsx 72 - const TodosListQuery = ` 73 - query ($from: Int!, $limit: Int!) { 74 - todos (from: $from, limit: $limit) { 75 - id 76 - title 77 - } 78 - } 79 - `; 80 - 81 - const Todos = ({ from, limit }) => { 82 - const [result, reexecuteQuery] = useQuery({ 83 - query: TodosListQuery, 84 - variables: { from, limit }, 85 - }); 86 - 87 - // ... 88 - }; 89 - ``` 90 - 91 - As when we're sending GraphQL queries manually using `fetch`, the variables will be attached to the 92 - `POST` request body that is sent to our GraphQL API. 93 - 94 - Whenever the `variables` (or the `query`) option on the `useQuery` hook changes `fetching` will 95 - switch to `true` and a new request will be sent to our API, unless a result has already been cached 96 - previously. 97 - 98 - ### Pausing `useQuery` 99 - 100 - In some cases we may want `useQuery` to execute a query when a pre-condition has been met, and not 101 - execute the query otherwise. For instance, we may be building a form and want a validation query to 102 - only take place when a field has been filled out. 103 - 104 - Since hooks in React can't just be commented out, the `useQuery` hook accepts a `pause` option that 105 - temporarily _freezes_ all changes and stops requests. 106 - 107 - In the previous example we've defined a query with mandatory arguments. The `$from` and `$limit` 108 - variables have been defined to be non-nullable `Int!` values. 109 - 110 - Let's pause the query we've just 111 - written to not execute when these variables are empty, to prevent `null` variables from being 112 - executed. We can do this by means of setting the `pause` option to `true`: 113 - 114 - ```jsx 115 - const Todos = ({ from, limit }) => { 116 - const [result, reexecuteQuery] = useQuery({ 117 - query: TodosListQuery, 118 - variables: { from, limit }, 119 - pause: !from || !limit, 120 - }); 121 - 122 - // ... 123 - }; 124 - ``` 125 - 126 - Now whenever the mandatory `$from` or `$limit` variables aren't supplied the query won't be executed. 127 - This also means that `result.data` won't change, which means we'll still have access to our old data 128 - even though the variables may have changed. 129 - 130 - ### Request Policies 131 - 132 - As has become clear in the previous sections of this page, the `useQuery` hook accepts more options 133 - than just `query` and `variables`. Another option we should touch on is `requestPolicy`. 134 - 135 - The `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By 136 - default this is set to `cache-first`, which means that we prefer to get results from our cache, but 137 - are falling back to sending an API request. 138 - 139 - In total there are four different policies that we can use: 140 - 141 - - `cache-first` (the default) prefers cached results and falls back to sending an API request when 142 - no prior result is cached. 143 - - `cache-and-network` returns cached results but also always sends an API request, which is perfect 144 - for displaying data quickly while keeping it up-to-date. 145 - - `network-only` will always send an API request and will ignore cached results. 146 - - `cache-only` will always return cached results or `null`. 147 - 148 - The `cache-and-network` policy is particularly useful, since it allows us to display data instantly 149 - if it has been cached, but also refreshes data in our cache in the background. This means though 150 - that `fetching` will be `false` for cached results although an API request may still be ongoing in 151 - the background. 152 - 153 - For this reason there's another field on results, `result.stale`, which indicates that the cached 154 - result is either outdated or that another request is being sent in the background. 155 - 156 - Request policies aren't specific to `urql`'s React API, but are a common feature in its core. [You 157 - can learn more about request policies on the API docs.](../api/core.md#requestpolicy) 158 - 159 - ### Reexecuting Queries 160 - 161 - The `useQuery` hook updates and executes queries whenever its inputs, like the `query` or 162 - `variables` change, but in some cases we may find that we need to programmatically trigger a new 163 - query. This is the purpose of the `reexecuteQuery` function which is the second item in the tuple 164 - that `useQuery` returns. 165 - 166 - Triggering a query programmatically may be useful in a couple of cases. It can for instance be used 167 - to refresh data that is currently being displayed. In these cases we may also override the 168 - `requestPolicy` of our query just once and set it to `network-only` to skip the cache. 169 - 170 - ```jsx 171 - const Todos = ({ from, limit }) => { 172 - const [result, reexecuteQuery] = useQuery({ 173 - query: TodosListQuery, 174 - variables: { from, limit }, 175 - }); 176 - 177 - const refresh = () => { 178 - // Refetch the query and skip the cache 179 - reexecuteQuery({ requestPolicy: 'network-only' }); 180 - }; 181 - }; 182 - ``` 183 - 184 - Calling `refresh` in the above example will execute the query again forcefully, and will skip the 185 - cache, since we're passing `requestPolicy: 'network-only'`. 186 - 187 - Furthermore the `reexecuteQuery` function can also be used to programmatically start a query even 188 - when `pause` is set to `true`, which would usually stop all automatic queries. 189 - 190 - ### Reading on 191 - 192 - There are some more tricks we can use with `useQuery`. [Read more about its API in the API docs for 193 - it.](../api/urql.md#usequery) 194 - 195 - [On the next page we'll learn about "Mutations" rather than Queries.](./mutations.md#react--preact) 196 - 197 - ## Svelte 198 - 199 - This guide covers how to query data with Svelte with our `Client` now fully set up and provided via 200 - the Context API. We'll implement queries using the `operationStore` and the `query` function from 201 - `@urql/svelte`. 202 - 203 - The `operationStore` function creates a [Svelte Writable store](https://svelte.dev/docs#writable). 204 - You can use it to initialise a data container in `urql`. This store holds on to our query inputs, 205 - like the GraphQL query and variables, which we can change to launch new queries, and also exposes 206 - the query's eventual result, which we can then observe. 207 - 208 - ### Run a first query 209 - 210 - For the following examples, we'll imagine that we're querying data from a GraphQL API that contains 211 - todo items. Let's dive right into it! 212 - 213 - ```jsx 214 - <script> 215 - import { operationStore, query } from '@urql/svelte'; 216 - 217 - const todos = operationStore(` 218 - query { 219 - todos { 220 - id 221 - title 222 - } 223 - } 224 - `); 225 - 226 - query(todos); 227 - </script> 228 - 229 - {#if $todos.fetching} 230 - <p>Loading...</p> 231 - {:else if $todos.error} 232 - <p>Oh no... {$todos.error.message}</p> 233 - {:else} 234 - <ul> 235 - {#each $todos.data.todos as todo} 236 - <li>{todo.title}</li> 237 - {/each} 238 - </ul> 239 - {/if} 240 - ``` 241 - 242 - Here we have implemented our first GraphQL query to fetch todos. We're first creating an 243 - `operationStore` which holds on to our `query` and are then passing the store to the `query` 244 - function, which starts the GraphQL query. 245 - 246 - The `todos` store can now be used like any other Svelte store using a 247 - [reactive auto-subscription](https://svelte.dev/tutorial/auto-subscriptions) in Svelte. This means 248 - that we prefix `$todos` with a dollar symbol, which automatically subscribes us to its changes. 249 - 250 - The `query` function accepts our store and starts using the `Client` to execute our query. It may 251 - only be called once for a store and lives alongside the component's lifecycle. It will automatically 252 - read changes on the `operationStore` and will update our query and results accordingly. 253 - 254 - ### Variables 255 - 256 - Typically we'll also need to pass variables to our queries, for instance, if we are dealing with 257 - pagination. For this purpose the `operationStore` also accepts a `variables` argument, which we can 258 - use to supply variables to our query. 259 - 260 - ```jsx 261 - <script> 262 - import { operationStore, query } from '@urql/svelte'; 263 - 264 - const todos = operationStore(` 265 - query ($from: Int!, $limit: Int!) { 266 - todos(from: $from, limit: $limit) { 267 - id 268 - title 269 - } 270 - }`, 271 - { from, limit } 272 - ); 273 - 274 - query(todos); 275 - </script> 276 - 277 - ... 278 - ``` 279 - 280 - As when we're sending GraphQL queries manually using `fetch`, the variables will be attached to the 281 - `POST` request body that is sent to our GraphQL API. 282 - 283 - The `operationStore` also supports being actively changed. This will hook into Svelte's reactivity 284 - model as well and cause the `query` utility to start a new operation. 285 - 286 - ```jsx 287 - <script> 288 - import { operationStore, query } from '@urql/svelte'; 289 - 290 - const todos = operationStore(` 291 - query ($from: Int!, $limit: Int!) { 292 - todos(from: $from, limit: $limit) { 293 - id 294 - title 295 - } 296 - }`, 297 - { from, limit } 298 - ); 299 - 300 - query(todos); 301 - 302 - function nextPage() { 303 - $todos.variables.from += $todos.variables.limit; 304 - } 305 - </script> 306 - 307 - <button on:click={nextPage}>Next page<button></button></button> 308 - ``` 309 - 310 - The `operationStore` provides getters too so it's also possible for us to pass `todos` around and 311 - update `todos.variables` or `todos.query` directly. Both, updating `todos.variables` and 312 - `$todos.variables` in a component for instance, will cause `query` to pick up the update and execute 313 - our changes. 314 - 315 - ### Pausing Queries 316 - 317 - In some cases we may want our queries to not execute until a pre-condition has been met. Since the 318 - `query` operation exists for the entire component lifecycle however, it can't just be stopped and 319 - started at will. Instead, the `query`'s third argument, the `context`, may have an added `pause` 320 - option that can be set to `true` to temporarily _freeze_ all changes and stop requests. 321 - 322 - For instance we may start out with a paused store and then unpause it once a callback is invoked: 323 - 324 - ```html 325 - <script> 326 - import { operationStore, query } from '@urql/svelte'; 327 - 328 - const todo = operationStore( 329 - ` 330 - query { 331 - todo { 332 - id 333 - title 334 - } 335 - }`, 336 - undefined, 337 - { pause: true } 338 - ); 339 - 340 - query(todo); 341 - 342 - function unpause() { 343 - $todo.context.pause = false; 344 - } 345 - </script> 346 - 347 - <button on:click={unpause}>Unpause</button> 348 - ``` 349 - 350 - ### Request Policies 351 - 352 - The `operationStore` also accepts another argument apart from `query` and `variables`. Optionally 353 - you may pass a third argument, [the `context` object](../api/core.md#operationcontext). The arguably 354 - most interesting option the `context` may contain is `requestPolicy`. 355 - 356 - The `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By 357 - default this is set to `cache-first`, which means that we prefer to get results from our cache, but 358 - are falling back to sending an API request. 359 - 360 - In total there are four different policies that we can use: 361 - 362 - - `cache-first` (the default) prefers cached results and falls back to sending an API request when 363 - no prior result is cached. 364 - - `cache-and-network` returns cached results but also always sends an API request, which is perfect 365 - for displaying data quickly while keeping it up-to-date. 366 - - `network-only` will always send an API request and will ignore cached results. 367 - - `cache-only` will always return cached results or `null`. 368 - 369 - The `cache-and-network` policy is particularly useful, since it allows us to display data instantly 370 - if it has been cached, but also refreshes data in our cache in the background. This means though 371 - that `fetching` will be `false` for cached results although an API request may still be ongoing in 372 - the background. 373 - 374 - For this reason there's another field on results, `result.stale`, which indicates that the cached 375 - result is either outdated or that another request is being sent in the background. 376 - 377 - ```jsx 378 - <script> 379 - import { operationStore, query } from '@urql/svelte'; 380 - 381 - const todos = operationStore(` 382 - query ($from: Int!, $limit: Int!) { 383 - todos(from: $from, limit: $limit) { 384 - id 385 - title 386 - } 387 - }`, 388 - { from, limit }, 389 - { requestPolicy: 'cache-and-network' } 390 - ); 391 - 392 - query(todos); 393 - </script> 394 - 395 - ... 396 - ``` 397 - 398 - As we can see, the `requestPolicy` is easily changed here and we can read our `context` option back 399 - from `todos.context`, just as we can check `todos.query` and `todos.variables`. Updating 400 - `operationStore.context` can be very useful to also refetch queries, as we'll see in the next 401 - section. 402 - 403 - [You can learn more about request policies on the API docs.](../api/core.md#requestpolicy) 404 - 405 - ### Reexecuting Queries 406 - 407 - The default caching approach in `@urql/svelte` typically takes care of updating queries on the fly 408 - quite well and does so automatically. Sometimes it may be necessary though to refetch data and to 409 - execute a query with a different `context`. Triggering a query programmatically may be useful in a 410 - couple of cases. It can for instance be used to refresh data that is currently being displayed. 411 - 412 - We can trigger a new query update by changing out the `context` of our `operationStore`. 413 - 414 - ```jsx 415 - <script> 416 - import { operationStore, query } from '@urql/svelte'; 417 - 418 - const todos = operationStore(` 419 - query ($from: Int!, $limit: Int!) { 420 - todos(from: $from, limit: $limit) { 421 - id 422 - title 423 - } 424 - }`, 425 - { from, limit }, 426 - { requestPolicy: 'cache-first' } 427 - ); 428 - 429 - query(todos); 430 - 431 - function refresh() { 432 - $todos.context = { requestPolicy: 'network-only' }; 433 - } 434 - </script> 435 - ``` 436 - 437 - Calling `refresh` in the above example will execute the query again forcefully, and will skip the 438 - cache, since we're passing `requestPolicy: 'network-only'`. 439 - 440 - ### Reading on 441 - 442 - There are some more tricks we can use with `operationStore`. 443 - [Read more about its API in the API docs for it.](../api/svelte.md#operationStore) 444 - 445 - [On the next page we'll learn about "Mutations" rather than Queries.](./mutations.md#svelte) 446 - 447 - ## Vue 448 - 449 - This guide covers how to query data with Vue with our `Client` now fully set up and provided to an 450 - app. We'll implement queries using the `useQuery` function from `@urql/vue`. 451 - 452 - ### Run a first query 453 - 454 - For the following examples, we'll imagine that we're querying data from a GraphQL API that contains 455 - todo items. Let's dive right into it! 456 - 457 - ```jsx 458 - <template> 459 - <div v-if="fetching"> 460 - Loading... 461 - </div> 462 - <div v-else-if="error"> 463 - Oh no... {{error}} 464 - </div> 465 - <div v-else> 466 - <ul v-if="data"> 467 - <li v-for="todo in data.todos">{{ todo.title }}</li> 468 - </ul> 469 - </div> 470 - </template> 471 - 472 - <script> 473 - import { useQuery } from '@urql/vue'; 474 - 475 - export default { 476 - setup() { 477 - const result = useQuery({ 478 - query: ` 479 - { 480 - todos { 481 - id 482 - title 483 - } 484 - } 485 - ` 486 - }); 487 - 488 - return { 489 - fetching: result.fetching, 490 - data: result.data, 491 - error: result.error, 492 - }; 493 - } 494 - }; 495 - </script> 496 - ``` 497 - 498 - Here we have implemented our first GraphQL query to fetch todos. We see that `useQuery` accepts 499 - options and returns a tuple. In this case we've set the `query` option to our GraphQL query. The 500 - tuple we then get in return is an array that contains a result object and a re-execute function. 501 - 502 - The result object contains several properties. The `fetching` field indicates whether we're currently 503 - loading data, `data` contains the actual `data` from the API's result, and `error` is set when either 504 - the request to the API has failed or when our API result contained some `GraphQLError`s, which 505 - we'll get into later on the ["Errors" page](./errors.md). 506 - 507 - All of these properties on the result are derived from the [shape of 508 - `OperationResult`](../api/core.md#operationresult) and are marked as [reactive 509 - ](https://v3.vuejs.org/guide/reactivity-fundamentals.html), which means they may 510 - update while the query is running, which will automatically update your UI. 511 - 512 - ### Variables 513 - 514 - Typically we'll also need to pass variables to our queries, for instance, if we are dealing with 515 - pagination. For this purpose `useQuery` also accepts a `variables` input, which we can 516 - use to supply variables to our query. 517 - 518 - ```jsx 519 - <template> 520 - ... 521 - </template> 522 - 523 - <script> 524 - import { useQuery } from '@urql/vue'; 525 - 526 - export default { 527 - props: ['from', 'limit'], 528 - setup({ from, limit }) { 529 - return useQuery({ 530 - query: ` 531 - query ($from: Int!, $limit: Int!) { 532 - todos(from: $from, limit: $limit) { 533 - id 534 - title 535 - } 536 - } 537 - `, 538 - variables: { from, limit } 539 - }); 540 - } 541 - }; 542 - </script> 543 - ``` 544 - 545 - As when we're sending GraphQL queries manually using `fetch`, the variables will be attached to the 546 - `POST` request body that is sent to our GraphQL API. 547 - 548 - All inputs that are passed to `useQuery` may also be [reactive 549 - state](https://v3.vuejs.org/guide/reactivity-fundamentals.html). This means that both the inputs and 550 - outputs of `useQuery` are reactive and may change over time. 551 - 552 - ```jsx 553 - <template> 554 - <ul v-if="data"> 555 - <li v-for="todo in data.todos">{{ todo.title }}</li> 556 - </ul> 557 - <button @click="from += 10">Next Page</button> 558 - </template> 559 - 560 - <script> 561 - import { useQuery } from '@urql/vue'; 562 - 563 - export default { 564 - setup() { 565 - const from = ref(0); 566 - 567 - const result = useQuery({ 568 - query: ` 569 - query ($from: Int!, $limit: Int!) { 570 - todos(from: $from, limit: $limit) { 571 - id 572 - title 573 - } 574 - } 575 - `, 576 - variables: { from, limit: 10 } 577 - }); 578 - 579 - return { 580 - from, 581 - data: result.data, 582 - }; 583 - } 584 - }; 585 - </script> 586 - ``` 587 - 588 - ### Pausing `useQuery` 589 - 590 - In some cases we may want `useQuery` to execute a query when a pre-condition has been met, and not 591 - execute the query otherwise. For instance, we may be building a form and want a validation query to 592 - only take place when a field has been filled out. 593 - 594 - Since with Vue 3's Composition API we won't just conditionally call `useQuery` we can instead pass a 595 - reactive `pause` input to `useQuery`. 596 - 597 - In the previous example we've defined a query with mandatory arguments. The `$from` and `$limit` 598 - variables have been defined to be non-nullable `Int!` values. 599 - 600 - Let's pause the query we've just written to not execute when these variables are empty, to 601 - prevent `null` variables from being executed. We can do this by computing `pause` to become `true` 602 - whenever these variables are falsy: 603 - 604 - ```js 605 - import { reactive } from 'vue' 606 - import { useQuery } from '@urql/vue'; 607 - 608 - export default { 609 - props: ['from', 'limit'], 610 - setup({ from, limit }) { 611 - return useQuery({ 612 - query: ` 613 - query ($from: Int!, $limit: Int!) { 614 - todos(from: $from, limit: $limit) { 615 - id 616 - title 617 - } 618 - } 619 - `, 620 - variables: { from, limit }, 621 - pause: computed(() => !from.value || !limit.value) 622 - }); 623 - } 624 - }; 625 - </script> 626 - ``` 627 - 628 - Now whenever the mandatory `$from` or `$limit` variables aren't supplied the query won't be executed. 629 - This also means that `result.data` won't change, which means we'll still have access to our old data 630 - even though the variables may have changed. 631 - 632 - It's worth noting that depending on whether `from` and `limit` are reactive or not you may have to 633 - change how `pause` is computed. But there's also an imperative alternative to this API. Not only 634 - does the result you get back from `useQuery` have an `isPaused` ref, it also has `pause()` and 635 - `resume()` methods. 636 - 637 - ```jsx 638 - <template> 639 - <div v-if="fetching"> 640 - Loading... 641 - </div> 642 - <button @click="isPaused ? resume() : pause()">Toggle Query</button> 643 - </template> 644 - 645 - <script> 646 - import { useQuery } from '@urql/vue'; 647 - 648 - export default { 649 - setup() { 650 - return useQuery({ 651 - query: ` 652 - { 653 - todos { 654 - id 655 - title 656 - } 657 - } 658 - ` 659 - }); 660 - } 661 - }; 662 - </script> 663 - ``` 664 - 665 - This means that no matter whether you're in or outside of `setup()` or rather supplying the inputs 666 - to `useQuery` or using the outputs, you'll have access to ways to pause or unpause the query. 667 - 668 - ### Request Policies 669 - 670 - As has become clear in the previous sections of this page, the `useQuery` hook accepts more options 671 - than just `query` and `variables`. Another option we should touch on is `requestPolicy`. 672 - 673 - The `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By 674 - default this is set to `cache-first`, which means that we prefer to get results from our cache, but 675 - are falling back to sending an API request. 676 - 677 - In total there are four different policies that we can use: 678 - 679 - - `cache-first` (the default) prefers cached results and falls back to sending an API request when 680 - no prior result is cached. 681 - - `cache-and-network` returns cached results but also always sends an API request, which is perfect 682 - for displaying data quickly while keeping it up-to-date. 683 - - `network-only` will always send an API request and will ignore cached results. 684 - - `cache-only` will always return cached results or `null`. 685 - 686 - The `cache-and-network` policy is particularly useful, since it allows us to display data instantly 687 - if it has been cached, but also refreshes data in our cache in the background. This means though 688 - that `fetching` will be `false` for cached results although an API request may still be ongoing in 689 - the background. 690 - 691 - For this reason there's another field on results, `result.stale`, which indicates that the cached 692 - result is either outdated or that another request is being sent in the background. 693 - 694 - Request policies aren't specific to `urql`'s Vue bindings, but are a common feature in its core. [You 695 - can learn more about request policies on the API docs.](../api/core.md#requestpolicy) 696 - 697 - ### Reexecuting Queries 698 - 699 - The `useQuery` hook updates and executes queries whenever its inputs, like the `query` or 700 - `variables` change, but in some cases we may find that we need to programmatically trigger a new 701 - query. This is the purpose of the `executeQuery` method which is a method on the result object 702 - that `useQuery` returns. 703 - 704 - Triggering a query programmatically may be useful in a couple of cases. It can for instance be used 705 - to refresh data that is currently being displayed. In these cases we may also override the 706 - `requestPolicy` of our query just once and set it to `network-only` to skip the cache. 707 - 708 - ```js 709 - import { useQuery } from '@urql/vue'; 710 - 711 - export default { 712 - setup() { 713 - const result = useQuery({ 714 - query: ` 715 - { 716 - todos { 717 - id 718 - title 719 - } 720 - } 721 - ` 722 - }); 723 - 724 - return { 725 - data: result.data, 726 - fetching: result.fetching, 727 - error: result.error, 728 - refresh() { 729 - result.executeQuery({ 730 - requestPolicy: 'network-only' 731 - }); 732 - } 733 - }; 734 - } 735 - }; 736 - </script> 737 - ``` 738 - 739 - Calling `refresh` in the above example will execute the query again forcefully, and will skip the 740 - cache, since we're passing `requestPolicy: 'network-only'`. 741 - 742 - Furthermore the `executeQuery` method can also be used to programmatically start a query even 743 - when `pause` is `true`, which would usually stop all automatic queries. 744 - 745 - ### Vue Suspense 746 - 747 - In Vue 3 a [new feature was introduced](https://vuedose.tips/go-async-in-vue-3-with-suspense/) that 748 - natively allows components to suspend while data is loading, which works universally on the server 749 - and on the client, where a replacement loading template is rendered on a parent while data is 750 - loading. 751 - 752 - Any component's `setup()` function can be updated to instead be an `async setup()` function, in 753 - other words, to return a `Promise` instead of directly returning its data. This means that we can 754 - update any `setup()` function to make use of Suspense. 755 - 756 - The `useQuery`'s returned result supports this, since it is a `PromiseLike`. We can update one of 757 - our examples to have a suspending component by changing our usage of `useQuery`: 758 - 759 - ```jsx 760 - <template> 761 - <ul> 762 - <li v-for="todo in data.todos">{{ todo.title }}</li> 763 - </ul> 764 - </template> 765 - 766 - <script> 767 - import { useQuery } from '@urql/vue'; 768 - 769 - export default { 770 - async setup() { 771 - const { data, error } = await useQuery({ 772 - query: ` 773 - { 774 - todos { 775 - id 776 - title 777 - } 778 - } 779 - ` 780 - }); 781 - 782 - return { data }; 783 - } 784 - }; 785 - </script> 786 - ``` 787 - 788 - As we can see, `await useQuery(...)` here suspends the component and what we render will not have to 789 - handle the loading states of `useQuery` at all. Instead in Vue Suspense we'll have to wrap a parent 790 - component in a "Suspense boundary." This boundary is what switches a parent to a loading state while 791 - parts of its children are fetching data. The suspense promise is in essence "bubbling up" until it 792 - finds a "Suspense boundary". 793 - 794 - ``` 795 - <template> 796 - <Suspense> 797 - <template #default> 798 - <MyAsyncComponent /> 799 - </template> 800 - <template #fallback> 801 - <span>Loading...</span> 802 - </template> 803 - </Suspense> 804 - </template> 805 - ``` 806 - 807 - As long as any parent component is wrapping our component which uses `async setup()` in this 808 - boundary, we'll get Vue Suspense to work correctly and trigger this loading state. When a child 809 - suspends this component will switch to using its `#fallback` template rather than its `#default` 810 - template. 811 - 812 - ### Reading on 813 - 814 - There are some more tricks we can use with `useQuery`. [Read more about its API in the API docs for 815 - it.](../api/vue.md#usequery) 816 - 817 - [On the next page we'll learn about "Mutations" rather than Queries.](./mutations.md#vue) 818 - 819 - ## Core 820 - 821 - All framework bindings — meaning `urql`, `@urql/preact`, `@urql/svelte`, and `@urql/vue` — reexport 822 - all exports of our `@urql/core` core library. This package contains the 823 - [`Client`](../api/core.md#client), built-in exchanges, and other utilities that are shared between 824 - all bindings. 825 - 826 - ### gql 827 - 828 - A notable utility function is the `gql` tagged template literal function, which is a drop-in 829 - replacement for `graphql-tag`, if you're coming from other GraphQL clients. 830 - 831 - Wherever `urql` accepts a query document, you may either pass a string or a `DocumentNode`. `gql` is 832 - a utility that allows a `DocumentNode` to be created directly, and others to be interpolated into 833 - it, which is useful for fragments for instance. This function will often also mark GraphQL documents 834 - for syntax highlighting in most code editors. 835 - 836 - In most examples we may have passed a string to define a query document, like so: 837 - 838 - ```js 839 - const TodosQuery = ` 840 - query { 841 - todos { 842 - id 843 - title 844 - } 845 - } 846 - `; 847 - ``` 848 - 849 - We may also use the `gql` tag function to create a `DocumentNode` directly: 850 - 851 - ```js 852 - import { gql } from '@urql/core'; 853 - 854 - const TodosQuery = gql` 855 - query { 856 - todos { 857 - id 858 - title 859 - } 860 - } 861 - `; 862 - ``` 863 - 864 - Since all framework bindings also re-export `@urql/core`, we may also import `gql` from `'urql'`, 865 - `'@urql/svelte'` and other bindings directly. 866 - 867 - We can also start interpolating other documents into the tag function. This is useful to compose 868 - fragment documents into a larger query, since it's common to define fragments across components of 869 - an app to spread out data dependencies. If we accidentally use a duplicate fragment name in a 870 - document, `gql` will log a warning, since GraphQL APIs won't accept duplicate names. 871 - 872 - ```js 873 - import { gql } from '@urql/core'; 874 - 875 - const TodoFragment = gql` 876 - fragment SmallTodo on Todo { 877 - id 878 - title 879 - } 880 - `; 881 - 882 - const TodosQuery = gql` 883 - query { 884 - todos { 885 - ...TodoFragment 886 - } 887 - } 888 - 889 - ${TodoFragment} 890 - `; 891 - ``` 892 - 893 - ### Reading on 894 - 895 - There are some more utilities that `@urql/core` exports. [All of them are listed in the API docs for 896 - it.](../api/core.md) 897 - 898 - [Read more about the `@urql/core` library on the "Core Package" 899 - page.](https://formidable.com/open-source/urql/docs/concepts/core-package/) 900 - 901 -
+355
docs/basics/react-preact.md
··· 1 + --- 2 + title: React/Preact 3 + order: 0 4 + --- 5 + 6 + # React/Preact 7 + 8 + This guide covers how to install and setup `urql` and the `Client`, as well as query and mutate data, 9 + with React and Preact. Since the `urql` and `@urql/preact` packages share most of their API and are 10 + used in the same way, when reading the documentation on React, all examples are essentially the same, 11 + except that we'd want to use the `@urql/preact` package instead of the `urql` package. 12 + 13 + ## Getting started 14 + 15 + ### Installation 16 + 17 + Installing `urql` is as quick as you'd expect and you won't need any other packages to get started 18 + with at first. We'll install the package with our package manager of choice. 19 + 20 + ```sh 21 + yarn add urql graphql 22 + # or 23 + npm install --save urql graphql 24 + ``` 25 + 26 + To use `urql` with Preact, we have to install `@urql/preact` instead of `urql` and import from 27 + that package instead. Otherwise all examples for Preact will be the same. 28 + 29 + Most libraries related to GraphQL also need the `graphql` package to be installed as a peer 30 + dependency, so that they can adapt to your specific versioning requirements. That's why we'll need 31 + to install `graphql` alongside `urql`. 32 + 33 + Both the `urql` and `graphql` packages follow [semantic versioning](https://semver.org) and all 34 + `urql` packages will define a range of compatible versions of `graphql`. Watch out for breaking 35 + changes in the future however, in which case your package manager may warn you about `graphql` being 36 + out of the defined peer dependency range. 37 + 38 + ### Setting up the `Client` 39 + 40 + The `urql` and `@urql/preact` packages export a method called `createClient` which we can use to 41 + create the GraphQL client. This central `Client` manages all of our GraphQL requests and results. 42 + 43 + ```js 44 + import { createClient } from 'urql'; 45 + 46 + const client = createClient({ 47 + url: 'http://localhost:3000/graphql', 48 + }); 49 + ``` 50 + 51 + At the bare minimum we'll need to pass an API's `url` when we create a `Client` to get started. 52 + 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 55 + a function returning an options object. 56 + 57 + In the following example we'll add a token to each `fetch` request that our `Client` sends to our 58 + GraphQL API. 59 + 60 + ```js 61 + const client = createClient({ 62 + url: 'http://localhost:3000/graphql', 63 + fetchOptions: () => { 64 + const token = getToken(); 65 + return { 66 + headers: { authorization: token ? `Bearer ${token}` : '' }, 67 + }; 68 + }, 69 + }); 70 + ``` 71 + 72 + ### Providing the `Client` 73 + 74 + To make use of the `Client` in React & Preact we will have to provide it via the 75 + [Context API](https://reactjs.org/docs/context.html). This may be done with the help of 76 + the `Provider` export. 77 + 78 + ```jsx 79 + import { createClient, Provider } from 'urql'; 80 + 81 + const client = createClient({ 82 + url: 'http://localhost:3000/graphql', 83 + }); 84 + 85 + const App = () => ( 86 + <Provider value={client}> 87 + <YourRoutes /> 88 + </Provider> 89 + ); 90 + ``` 91 + 92 + Now every component and element inside and under the `Provider` are able to use GraphQL queries that 93 + will be sent to our API. 94 + 95 + ## Queries 96 + 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 99 + render-props components.](../api/urql.md#query-component) 100 + 101 + ### Run a first query 102 + 103 + For the following examples, we'll imagine that we're querying data from a GraphQL API that contains 104 + todo items. Let's dive right into it! 105 + 106 + ```jsx 107 + import { useQuery } from 'urql'; 108 + 109 + const TodosQuery = ` 110 + query { 111 + todos { 112 + id 113 + title 114 + } 115 + } 116 + `; 117 + 118 + const Todos = () => { 119 + const [result, reexecuteQuery] = useQuery({ 120 + query: TodosQuery, 121 + }); 122 + 123 + const { data, fetching, error } = result; 124 + 125 + if (fetching) return <p>Loading...</p>; 126 + if (error) return <p>Oh no... {error.message}</p>; 127 + 128 + return ( 129 + <ul> 130 + {data.todos.map(todo => ( 131 + <li key={todo.id}>{todo.title}</li> 132 + ))} 133 + </ul> 134 + ); 135 + }; 136 + ``` 137 + 138 + Here we have implemented our first GraphQL query to fetch todos. We see that `useQuery` accepts 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. 141 + 142 + The result object contains several properties. The `fetching` field indicates whether we're currently 143 + loading data, `data` contains the actual `data` from the API's result, and `error` is set when either 144 + the request to the API has failed or when our API result contained some `GraphQLError`s, which 145 + we'll get into later on the ["Errors" page](../concepts/errors.md). 146 + 147 + ### Variables 148 + 149 + Typically we'll also need to pass variables to our queries, for instance, if we are dealing with 150 + pagination. For this purpose the `useQuery` hook also accepts a `variables` option, which we can use 151 + to supply variables to our query. 152 + 153 + ```jsx 154 + const TodosListQuery = ` 155 + query ($from: Int!, $limit: Int!) { 156 + todos (from: $from, limit: $limit) { 157 + id 158 + title 159 + } 160 + } 161 + `; 162 + 163 + const Todos = ({ from, limit }) => { 164 + const [result, reexecuteQuery] = useQuery({ 165 + query: TodosListQuery, 166 + variables: { from, limit }, 167 + }); 168 + 169 + // ... 170 + }; 171 + ``` 172 + 173 + As when we're sending GraphQL queries manually using `fetch`, the variables will be attached to the 174 + `POST` request body that is sent to our GraphQL API. 175 + 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 178 + previously. 179 + 180 + ### Pausing `useQuery` 181 + 182 + In some cases we may want `useQuery` to execute a query when a pre-condition has been met, and not 183 + execute the query otherwise. For instance, we may be building a form and want a validation query to 184 + only take place when a field has been filled out. 185 + 186 + Since hooks in React can't just be commented out, the `useQuery` hook accepts a `pause` option that 187 + temporarily _freezes_ all changes and stops requests. 188 + 189 + In the previous example we've defined a query with mandatory arguments. The `$from` and `$limit` 190 + variables have been defined to be non-nullable `Int!` values. 191 + 192 + Let's pause the query we've just 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`: 195 + 196 + ```jsx 197 + const Todos = ({ from, limit }) => { 198 + const [result, reexecuteQuery] = useQuery({ 199 + query: TodosListQuery, 200 + variables: { from, limit }, 201 + pause: !from || !limit, 202 + }); 203 + 204 + // ... 205 + }; 206 + ``` 207 + 208 + Now whenever the mandatory `$from` or `$limit` variables aren't supplied the query won't be executed. 209 + This also means that `result.data` won't change, which means we'll still have access to our old data 210 + even though the variables may have changed. 211 + 212 + ### Request Policies 213 + 214 + As has become clear in the previous sections of this page, the `useQuery` hook accepts more options 215 + than just `query` and `variables`. Another option we should touch on is `requestPolicy`. 216 + 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 219 + are falling back to sending an API request. 220 + 221 + Request policies aren't specific to `urql`'s React API, but are a common feature in its core. [You 222 + can learn more about how the cache behaves given the four different policies on the "Document 223 + Caching" page.](../concepts/document-caching.md) 224 + 225 + ### Reexecuting Queries 226 + 227 + The `useQuery` hook updates and executes queries whenever its inputs, like the `query` or 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 230 + that `useQuery` returns. 231 + 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. 235 + 236 + ```jsx 237 + const Todos = ({ from, limit }) => { 238 + const [result, reexecuteQuery] = useQuery({ 239 + query: TodosListQuery, 240 + variables: { from, limit }, 241 + }); 242 + 243 + const refresh = () => { 244 + // Refetch the query and skip the cache 245 + reexecuteQuery({ requestPolicy: 'network-only' }); 246 + }; 247 + }; 248 + ``` 249 + 250 + Calling `refresh` in the above example will execute the query again forcefully, and will skip the 251 + cache, since we're passing `requestPolicy: 'network-only'`. 252 + 253 + Furthermore the `reexecuteQuery` function can also be used to programmatically start a query even 254 + when `pause` is set to `true`, which would usually stop all automatic queries. 255 + 256 + There are some more tricks we can use with `useQuery`. [Read more about its API in the API docs for 257 + it.](../api/urql.md#usequery) 258 + 259 + ## Mutations 260 + 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 263 + render-props components.](../api/urql.md#mutation-component) 264 + 265 + ### Sending a mutation 266 + 267 + Let's again pick up an example with an imaginary GraphQL API for todo items, and dive into an 268 + example! We'll set up a mutation that _updates_ a todo item's title. 269 + 270 + ```jsx 271 + const UpdateTodo = ` 272 + mutation ($id: ID!, $title: String!) { 273 + updateTodo (id: $id, title: $title) { 274 + id 275 + title 276 + } 277 + } 278 + `; 279 + 280 + const Todo = ({ id, title }) => { 281 + const [updateTodoResult, updateTodo] = useMutation(UpdateTodo); 282 + }; 283 + ``` 284 + 285 + Similar to the `useQuery` output, `useMutation` returns a tuple. The first item in the tuple again 286 + contains `fetching`, `error`, and `data` — it's identical since this is a common pattern of how 287 + `urql` presents [operation results](../api/core.md#operationresult). 288 + 289 + Unlike the `useQuery` hook, the `useMutation` hook doesn't execute automatically. At this point in 290 + our example, no mutation will be performed. To execute our mutation we instead have to call the 291 + execute function — `updateTodo` in our example — which is the second item in the tuple. 292 + 293 + ### Using the mutation result 294 + 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 297 + we can use the promise that `updateTodo` returns. 298 + 299 + ```jsx 300 + const Todo = ({ id, title }) => { 301 + const [updateTodoResult, updateTodo] = useMutation(UpdateTodo); 302 + 303 + const submit = newTitle => { 304 + const variables = { id, title: newTitle || '' }; 305 + updateTodo(variables).then(result => { 306 + // The result is almost identical to `updateTodoResult` with the exception 307 + // of `result.fetching` not being set. 308 + // It is an OperationResult. 309 + }); 310 + }; 311 + }; 312 + ``` 313 + 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 316 + completed. 317 + 318 + ### Handling mutation errors 319 + 320 + It's worth noting that the promise we receive when calling the execute function will never 321 + reject. Instead it will always return a promise that resolves to a result. 322 + 323 + If you're checking for errors, you should use `result.error` instead, which will be set 324 + to a `CombinedError` when any kind of errors occurred while executing your mutation. 325 + [Read more about errors on our "Errors" page.](../concepts/errors.md) 326 + 327 + ```jsx 328 + const Todo = ({ id, title }) => { 329 + const [updateTodoResult, updateTodo] = useMutation(UpdateTodo); 330 + 331 + const submit = newTitle => { 332 + const variables = { id, title: newTitle || '' }; 333 + updateTodo(variables).then(result => { 334 + if (result.error) { 335 + console.error('Oh no!', result.error); 336 + } 337 + }); 338 + }; 339 + }; 340 + ``` 341 + 342 + There are some more tricks we can use with `useMutation`.<br /> 343 + [Read more about its API in the API docs for it.](../api/urql.md#usemutation) 344 + 345 + ## Reading on 346 + 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, 349 + which is the same between all framework bindings. Hence, next we may want to learn more about one of 350 + the following to learn more about the internals: 351 + 352 + - [How does the default "document cache" work?](../concepts/document-caching.md) 353 + - [How are errors handled and represented?](../concepts/errors.md) 354 + - [A quick overview of `urql`'s philosophy and structure.](../concepts/philosophy.md) 355 + - [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
+483
docs/basics/svelte.md
··· 1 + --- 2 + title: Svelte 3 + order: 2 4 + --- 5 + 6 + # Svelte 7 + 8 + ## Getting started 9 + 10 + This "Getting Started" guide covers how to install and set up `urql` and provide a `Client` for 11 + Svelte. The `@urql/svelte` package, which provides bindings for Svelte, doesn't fundamentally 12 + function differently from `@urql/preact` or `urql` and uses the same [Core Package and 13 + `Client`](../concepts/core-package.md). 14 + 15 + ### Installation 16 + 17 + Installing `@urql/svelte` is quick and no other packages are immediately necessary. 18 + 19 + ```sh 20 + yarn add @urql/svelte graphql 21 + # or 22 + npm install --save @urql/svelte graphql 23 + ``` 24 + 25 + Most libraries related to GraphQL also need the `graphql` package to be installed as a peer 26 + dependency, so that they can adapt to your specific versioning requirements. That's why we'll need 27 + to install `graphql` alongside `@urql/svelte`. 28 + 29 + Both the `@urql/svelte` and `graphql` packages follow [semantic versioning](https://semver.org) and 30 + all `@urql/svelte` packages will define a range of compatible versions of `graphql`. Watch out 31 + for breaking changes in the future however, in which case your package manager may warn you about 32 + `graphql` being out of the defined peer dependency range. 33 + 34 + ### Setting up the `Client` 35 + 36 + The `@urql/svelte` package exports a method called `createClient` which we can use to create 37 + the GraphQL client. This central `Client` manages all of our GraphQL requests and results. 38 + 39 + ```js 40 + import { createClient } from '@urql/svelte'; 41 + 42 + const client = createClient({ 43 + url: 'http://localhost:3000/graphql', 44 + }); 45 + ``` 46 + 47 + At the bare minimum we'll need to pass an API's `url` when we create a `Client` to get started. 48 + 49 + Another common option is `fetchOptions`. This option allows us to customize the options that will be 50 + passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or 51 + a function returning an options object. 52 + 53 + In the following example we'll add a token to each `fetch` request that our `Client` sends to our 54 + GraphQL API. 55 + 56 + ```js 57 + const client = createClient({ 58 + url: 'http://localhost:3000/graphql', 59 + fetchOptions: () => { 60 + const token = getToken(); 61 + return { 62 + headers: { authorization: token ? `Bearer ${token}` : '' }, 63 + }; 64 + }, 65 + }); 66 + ``` 67 + 68 + ### Providing the `Client` 69 + 70 + To make use of the `Client` in Svelte we will have to provide it via the 71 + [Context API](https://svelte.dev/tutorial/context-api). From a parent component to its child 72 + components. This will share one `Client` with the rest of our app, if we for instance provide the 73 + `Client` 74 + 75 + ```html 76 + <script> 77 + import { createClient, setClient } from '@urql/svelte'; 78 + 79 + const client = createClient({ 80 + url: 'http://localhost:3000/graphql', 81 + }); 82 + 83 + setClient(client); 84 + </script> 85 + ``` 86 + 87 + The `setClient` method internally calls [Svelte's `setContext` 88 + function](https://svelte.dev/docs#setContext). The `@urql/svelte` package also exposes a `getClient` 89 + function that uses [`getContext`](https://svelte.dev/docs#getContext) to retrieve the `Client` in 90 + child components. This is used throughout `@urql/svelte`'s API. 91 + 92 + We can also use a convenience function, `initClient`. This function combines the `createClient` and 93 + `setClient` calls into one. 94 + 95 + ```html 96 + <script> 97 + import { initClient } from '@urql/svelte'; 98 + 99 + initClient({ 100 + url: 'http://localhost:3000/graphql', 101 + }); 102 + </script> 103 + ``` 104 + 105 + ## Queries 106 + 107 + We'll implement queries using the `operationStore` and the `query` function from `@urql/svelte`. 108 + 109 + The `operationStore` function creates a [Svelte Writable store](https://svelte.dev/docs#writable). 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 112 + the query's eventual result, which we can then observe. 113 + 114 + ### Run a first query 115 + 116 + For the following examples, we'll imagine that we're querying data from a GraphQL API that contains 117 + todo items. Let's dive right into it! 118 + 119 + ```jsx 120 + <script> 121 + import { operationStore, query } from '@urql/svelte'; 122 + 123 + const todos = operationStore(` 124 + query { 125 + todos { 126 + id 127 + title 128 + } 129 + } 130 + `); 131 + 132 + query(todos); 133 + </script> 134 + 135 + {#if $todos.fetching} 136 + <p>Loading...</p> 137 + {:else if $todos.error} 138 + <p>Oh no... {$todos.error.message}</p> 139 + {:else} 140 + <ul> 141 + {#each $todos.data.todos as todo} 142 + <li>{todo.title}</li> 143 + {/each} 144 + </ul> 145 + {/if} 146 + ``` 147 + 148 + Here we have implemented our first GraphQL query to fetch todos. We're first creating an 149 + `operationStore` which holds on to our `query` and are then passing the store to the `query` 150 + function, which starts the GraphQL query. 151 + 152 + The `todos` store can now be used like any other Svelte store using a 153 + [reactive auto-subscription](https://svelte.dev/tutorial/auto-subscriptions) in Svelte. This means 154 + that we prefix `$todos` with a dollar symbol, which automatically subscribes us to its changes. 155 + 156 + The `query` function accepts our store and starts using the `Client` to execute our query. It may 157 + only be called once for a store and lives alongside the component's lifecycle. It will automatically 158 + read changes on the `operationStore` and will update our query and results accordingly. 159 + 160 + ### Variables 161 + 162 + Typically we'll also need to pass variables to our queries, for instance, if we are dealing with 163 + pagination. For this purpose the `operationStore` also accepts a `variables` argument, which we can 164 + use to supply variables to our query. 165 + 166 + ```jsx 167 + <script> 168 + import { operationStore, query } from '@urql/svelte'; 169 + 170 + const todos = operationStore(` 171 + query ($from: Int!, $limit: Int!) { 172 + todos(from: $from, limit: $limit) { 173 + id 174 + title 175 + } 176 + }`, 177 + { from, limit } 178 + ); 179 + 180 + query(todos); 181 + </script> 182 + 183 + ... 184 + ``` 185 + 186 + As when we're sending GraphQL queries manually using `fetch`, the variables will be attached to the 187 + `POST` request body that is sent to our GraphQL API. 188 + 189 + The `operationStore` also supports being actively changed. This will hook into Svelte's reactivity 190 + model as well and cause the `query` utility to start a new operation. 191 + 192 + ```jsx 193 + <script> 194 + import { operationStore, query } from '@urql/svelte'; 195 + 196 + const todos = operationStore(` 197 + query ($from: Int!, $limit: Int!) { 198 + todos(from: $from, limit: $limit) { 199 + id 200 + title 201 + } 202 + }`, 203 + { from, limit } 204 + ); 205 + 206 + query(todos); 207 + 208 + function nextPage() { 209 + $todos.variables.from += $todos.variables.limit; 210 + } 211 + </script> 212 + 213 + <button on:click={nextPage}>Next page<button></button></button> 214 + ``` 215 + 216 + The `operationStore` provides getters too so it's also possible for us to pass `todos` around and 217 + update `todos.variables` or `todos.query` directly. Both, updating `todos.variables` and 218 + `$todos.variables` in a component for instance, will cause `query` to pick up the update and execute 219 + our changes. 220 + 221 + ### Pausing Queries 222 + 223 + In some cases we may want our queries to not execute until a pre-condition has been met. Since the 224 + `query` operation exists for the entire component lifecycle however, it can't just be stopped and 225 + started at will. Instead, the `query`'s third argument, the `context`, may have an added `pause` 226 + option that can be set to `true` to temporarily _freeze_ all changes and stop requests. 227 + 228 + For instance we may start out with a paused store and then unpause it once a callback is invoked: 229 + 230 + ```html 231 + <script> 232 + import { operationStore, query } from '@urql/svelte'; 233 + 234 + const todo = operationStore( 235 + ` 236 + query { 237 + todo { 238 + id 239 + title 240 + } 241 + }`, 242 + undefined, 243 + { pause: true } 244 + ); 245 + 246 + query(todo); 247 + 248 + function unpause() { 249 + $todo.context.pause = false; 250 + } 251 + </script> 252 + 253 + <button on:click="{unpause}">Unpause</button> 254 + ``` 255 + 256 + ### Request Policies 257 + 258 + The `operationStore` also accepts another argument apart from `query` and `variables`. Optionally 259 + you may pass a third argument, [the `context` object](../api/core.md#operationcontext). The arguably 260 + most interesting option the `context` may contain is `requestPolicy`. 261 + 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 264 + are falling back to sending an API request. 265 + 266 + In total there are four different policies that we can use: 267 + 268 + - `cache-first` (the default) prefers cached results and falls back to sending an API request when 269 + no prior result is cached. 270 + - `cache-and-network` returns cached results but also always sends an API request, which is perfect 271 + for displaying data quickly while keeping it up-to-date. 272 + - `network-only` will always send an API request and will ignore cached results. 273 + - `cache-only` will always return cached results or `null`. 274 + 275 + The `cache-and-network` policy is particularly useful, since it allows us to display data instantly 276 + if it has been cached, but also refreshes data in our cache in the background. This means though 277 + that `fetching` will be `false` for cached results although an API request may still be ongoing in 278 + the background. 279 + 280 + For this reason there's another field on results, `result.stale`, which indicates that the cached 281 + result is either outdated or that another request is being sent in the background. 282 + 283 + ```jsx 284 + <script> 285 + import { operationStore, query } from '@urql/svelte'; 286 + 287 + const todos = operationStore(` 288 + query ($from: Int!, $limit: Int!) { 289 + todos(from: $from, limit: $limit) { 290 + id 291 + title 292 + } 293 + }`, 294 + { from, limit }, 295 + { requestPolicy: 'cache-and-network' } 296 + ); 297 + 298 + query(todos); 299 + </script> 300 + 301 + ... 302 + ``` 303 + 304 + As we can see, the `requestPolicy` is easily changed here and we can read our `context` option back 305 + from `todos.context`, just as we can check `todos.query` and `todos.variables`. Updating 306 + `operationStore.context` can be very useful to also refetch queries, as we'll see in the next 307 + section. 308 + 309 + [You can learn more about request policies on the API docs.](../api/core.md#requestpolicy) 310 + 311 + ### Reexecuting Queries 312 + 313 + The default caching approach in `@urql/svelte` typically takes care of updating queries on the fly 314 + quite well and does so automatically. Sometimes it may be necessary though to refetch data and to 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. 317 + 318 + We can trigger a new query update by changing out the `context` of our `operationStore`. 319 + 320 + ```jsx 321 + <script> 322 + import { operationStore, query } from '@urql/svelte'; 323 + 324 + const todos = operationStore(` 325 + query ($from: Int!, $limit: Int!) { 326 + todos(from: $from, limit: $limit) { 327 + id 328 + title 329 + } 330 + }`, 331 + { from, limit }, 332 + { requestPolicy: 'cache-first' } 333 + ); 334 + 335 + query(todos); 336 + 337 + function refresh() { 338 + $todos.context = { requestPolicy: 'network-only' }; 339 + } 340 + </script> 341 + ``` 342 + 343 + Calling `refresh` in the above example will execute the query again forcefully, and will skip the 344 + cache, since we're passing `requestPolicy: 'network-only'`. 345 + 346 + ### Reading on 347 + 348 + There are some more tricks we can use with `operationStore`. 349 + [Read more about its API in the API docs for it.](../api/svelte.md#operationStore) 350 + 351 + ## Mutations 352 + 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 355 + trusty `operationStore`. 356 + 357 + ### Sending a mutation 358 + 359 + Let's again pick up an example with an imaginary GraphQL API for todo items, and dive into an 360 + example! We'll set up a mutation that _updates_ a todo item's title. 361 + 362 + ```html 363 + <script> 364 + import { mutation } from '@urql/svelte'; 365 + 366 + export let id; 367 + 368 + const mutateTodo = mutation({ 369 + query: ` 370 + mutation ($id: ID!, $title: String!) { 371 + updateTodo (id: $id, title: $title) { 372 + id 373 + title 374 + } 375 + } 376 + `, 377 + }); 378 + 379 + function updateTodo(newTitle) { 380 + mutateTodo({ id, title: newTitle }); 381 + } 382 + </script> 383 + ``` 384 + 385 + This small call to `mutation` accepts a `query` property (besides the `variables` property) and 386 + returns an execute function. We've wrapped it in an `updateTodo` function to illustrate its usage. 387 + 388 + Unlike the `query` function, the `mutation` function doesn't start our mutation automatically. 389 + Instead, mutations are started programmatically by calling the function they return. This function 390 + also returns a promise so that we can use the mutation's result. 391 + 392 + ### Using the mutation result 393 + 394 + When calling `mutateTodo` in our previous example, we start the mutation. To use the mutation's 395 + result we actually have two options instead of one. 396 + 397 + The first option is to use the promise that the `mutation`'s execute function returns. This promise 398 + will resolve to an `operationStore`, which is what we're used to from sending queries. Using this 399 + store we can then read the mutation's `data` or `error`. 400 + 401 + ```html 402 + <script> 403 + import { mutation } from '@urql/svelte'; 404 + 405 + export let id; 406 + 407 + const mutateTodo = mutation({ 408 + query: ` 409 + mutation ($id: ID!, $title: String!) { 410 + updateTodo (id: $id, title: $title) { 411 + id 412 + title 413 + } 414 + } 415 + `, 416 + }); 417 + 418 + function updateTodo(newTitle) { 419 + mutateTodo({ id, title: newTitle }).then(result => { 420 + // The result is an operationStore again, which will already carry the mutation's result 421 + console.log(result.data, result.error); 422 + }); 423 + } 424 + </script> 425 + ``` 426 + 427 + Alternatively, we can pass `mutation` an `operationStore` directly. This allows us to use a 428 + mutation's result in our component's UI more easily, without storing it ourselves. 429 + 430 + ```html 431 + <script> 432 + import { operationStore, mutation } from '@urql/svelte'; 433 + 434 + export let id; 435 + 436 + const updateTodoStore = operationStore(` 437 + mutation ($id: ID!, $title: String!) { 438 + updateTodo (id: $id, title: $title) { 439 + id 440 + title 441 + } 442 + } 443 + `); 444 + 445 + const updateTodoMutation = mutation(updateTodoStore); 446 + 447 + function updateTodo(newTitle) { 448 + updateTodoMutation({ id, title: newTitle }); 449 + } 450 + </script> 451 + 452 + {#if $updateTodoStore.data} Todo was updated! {/if} 453 + ``` 454 + 455 + ### Handling mutation errors 456 + 457 + It's worth noting that the promise we receive when calling the execute function will never 458 + reject. Instead it will always return a promise that resolves to an `operationStore`, even if the 459 + mutation has failed. 460 + 461 + If you're checking for errors, you should use `operationStore.error` instead, which will be set 462 + to a `CombinedError` when any kind of errors occurred while executing your mutation. 463 + [Read more about errors on our "Errors" page.](../concepts/errors.md) 464 + 465 + ```jsx 466 + mutateTodo({ id, title: newTitle }).then(result => { 467 + if (result.error) { 468 + console.error('Oh no!', result.error); 469 + } 470 + }); 471 + ``` 472 + 473 + ## Reading on 474 + 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, 477 + which is the same between all framework bindings. Hence, next we may want to learn more about one of 478 + the following to learn more about the internals: 479 + 480 + - [How does the default "document cache" work?](../concepts/document-caching.md) 481 + - [How are errors handled and represented?](../concepts/errors.md) 482 + - [A quick overview of `urql`'s philosophy and structure.](../concepts/philosophy.md) 483 + - [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
+606
docs/basics/vue.md
··· 1 + --- 2 + title: Vue 3 + order: 1 4 + --- 5 + 6 + # Vue 7 + 8 + ## Getting started 9 + 10 + The `@urql/vue` bindings have been written with [Vue 11 + 3](https://github.com/vuejs/vue-next/releases/tag/v3.0.0) in mind and use Vue's newer [Composition 12 + API](https://v3.vuejs.org/guide/composition-api-introduction.html). This gives the `@urql/vue` 13 + bindings capabilities to be more easily integrated into your existing `setup()` functions. 14 + 15 + ### Installation 16 + 17 + Installing `@urql/vue` is quick and no other packages are immediately necessary. 18 + 19 + ```sh 20 + yarn add @urql/vue graphql 21 + # or 22 + npm install --save @urql/vue graphql 23 + ``` 24 + 25 + Most libraries related to GraphQL also need the `graphql` package to be installed as a peer 26 + dependency, so that they can adapt to your specific versioning requirements. That's why we'll need 27 + to install `graphql` alongside `@urql/vue`. 28 + 29 + Both the `@urql/vue` and `graphql` packages follow [semantic versioning](https://semver.org) and 30 + all `@urql/vue` packages will define a range of compatible versions of `graphql`. Watch out 31 + for breaking changes in the future however, in which case your package manager may warn you about 32 + `graphql` being out of the defined peer dependency range. 33 + 34 + ### Setting up the `Client` 35 + 36 + The `@urql/vue` package exports a method called `createClient` which we can use to create 37 + the GraphQL client. This central `Client` manages all of our GraphQL requests and results. 38 + 39 + ```js 40 + import { createClient } from '@urql/vue'; 41 + 42 + const client = createClient({ 43 + url: 'http://localhost:3000/graphql', 44 + }); 45 + ``` 46 + 47 + At the bare minimum we'll need to pass an API's `url` when we create a `Client` to get started. 48 + 49 + Another common option is `fetchOptions`. This option allows us to customize the options that will be 50 + passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or 51 + a function returning an options object. 52 + 53 + In the following example we'll add a token to each `fetch` request that our `Client` sends to our 54 + GraphQL API. 55 + 56 + ```js 57 + const client = createClient({ 58 + url: 'http://localhost:3000/graphql', 59 + fetchOptions: () => { 60 + const token = getToken(); 61 + return { 62 + headers: { authorization: token ? `Bearer ${token}` : '' }, 63 + }; 64 + }, 65 + }); 66 + ``` 67 + 68 + ### Providing the `Client` 69 + 70 + To make use of the `Client` in Vue we will have to provide from a parent component to its child 71 + components. This will share one `Client` with the rest of our app. In `@urql/vue` there are two 72 + different ways to achieve this. 73 + 74 + The first method is to use `@urql/vue`'s `provideClient` function. This must be called in any of 75 + your parent components and accepts either a `Client` directly or just the options that you'd pass to 76 + `createClient`. 77 + 78 + ```html 79 + <script> 80 + import { createClient, provideClient } from '@urql/vue'; 81 + 82 + const client = createClient({ 83 + url: 'http://localhost:3000/graphql', 84 + }); 85 + 86 + provideClient(client); 87 + </script> 88 + ``` 89 + 90 + Alternatively we may use the exported `install` function and treat `@urql/vue` as a plugin by 91 + importing its default export and using it [as a plugin](https://v3.vuejs.org/guide/plugins.html#using-a-plugin). 92 + 93 + ```js 94 + import { createApp } from 'vue'; 95 + import Root from './App.vue'; 96 + import urql from '@urql/vue'; 97 + 98 + const app = createApp(Root); 99 + 100 + app.use(urql, { 101 + url: 'http://localhost:3000/graphql', 102 + }); 103 + 104 + app.mount('#app'); 105 + ``` 106 + 107 + The plugin also accepts `createClient`'s options or a `Client` as its inputs. 108 + 109 + ## Queries 110 + 111 + We'll implement queries using the `useQuery` function from `@urql/vue`. 112 + 113 + ### Run a first query 114 + 115 + For the following examples, we'll imagine that we're querying data from a GraphQL API that contains 116 + todo items. Let's dive right into it! 117 + 118 + ```jsx 119 + <template> 120 + <div v-if="fetching"> 121 + Loading... 122 + </div> 123 + <div v-else-if="error"> 124 + Oh no... {{error}} 125 + </div> 126 + <div v-else> 127 + <ul v-if="data"> 128 + <li v-for="todo in data.todos">{{ todo.title }}</li> 129 + </ul> 130 + </div> 131 + </template> 132 + 133 + <script> 134 + import { useQuery } from '@urql/vue'; 135 + 136 + export default { 137 + setup() { 138 + const result = useQuery({ 139 + query: ` 140 + { 141 + todos { 142 + id 143 + title 144 + } 145 + } 146 + ` 147 + }); 148 + 149 + return { 150 + fetching: result.fetching, 151 + data: result.data, 152 + error: result.error, 153 + }; 154 + } 155 + }; 156 + </script> 157 + ``` 158 + 159 + Here we have implemented our first GraphQL query to fetch todos. We see that `useQuery` accepts 160 + options and returns a tuple. In this case we've set the `query` option to our GraphQL query. The 161 + tuple we then get in return is an array that contains a result object and a re-execute function. 162 + 163 + The result object contains several properties. The `fetching` field indicates whether we're currently 164 + loading data, `data` contains the actual `data` from the API's result, and `error` is set when either 165 + the request to the API has failed or when our API result contained some `GraphQLError`s, which 166 + we'll get into later on the ["Errors" page](../concepts/errors.md). 167 + 168 + All of these properties on the result are derived from the [shape of 169 + `OperationResult`](../api/core.md#operationresult) and are marked as [reactive 170 + ](https://v3.vuejs.org/guide/reactivity-fundamentals.html), which means they may 171 + update while the query is running, which will automatically update your UI. 172 + 173 + ### Variables 174 + 175 + Typically we'll also need to pass variables to our queries, for instance, if we are dealing with 176 + pagination. For this purpose `useQuery` also accepts a `variables` input, which we can 177 + use to supply variables to our query. 178 + 179 + ```jsx 180 + <template> 181 + ... 182 + </template> 183 + 184 + <script> 185 + import { useQuery } from '@urql/vue'; 186 + 187 + export default { 188 + props: ['from', 'limit'], 189 + setup({ from, limit }) { 190 + return useQuery({ 191 + query: ` 192 + query ($from: Int!, $limit: Int!) { 193 + todos(from: $from, limit: $limit) { 194 + id 195 + title 196 + } 197 + } 198 + `, 199 + variables: { from, limit } 200 + }); 201 + } 202 + }; 203 + </script> 204 + ``` 205 + 206 + As when we're sending GraphQL queries manually using `fetch`, the variables will be attached to the 207 + `POST` request body that is sent to our GraphQL API. 208 + 209 + All inputs that are passed to `useQuery` may also be [reactive 210 + state](https://v3.vuejs.org/guide/reactivity-fundamentals.html). This means that both the inputs and 211 + outputs of `useQuery` are reactive and may change over time. 212 + 213 + ```jsx 214 + <template> 215 + <ul v-if="data"> 216 + <li v-for="todo in data.todos">{{ todo.title }}</li> 217 + </ul> 218 + <button @click="from += 10">Next Page</button> 219 + </template> 220 + 221 + <script> 222 + import { useQuery } from '@urql/vue'; 223 + 224 + export default { 225 + setup() { 226 + const from = ref(0); 227 + 228 + const result = useQuery({ 229 + query: ` 230 + query ($from: Int!, $limit: Int!) { 231 + todos(from: $from, limit: $limit) { 232 + id 233 + title 234 + } 235 + } 236 + `, 237 + variables: { from, limit: 10 } 238 + }); 239 + 240 + return { 241 + from, 242 + data: result.data, 243 + }; 244 + } 245 + }; 246 + </script> 247 + ``` 248 + 249 + ### Pausing `useQuery` 250 + 251 + In some cases we may want `useQuery` to execute a query when a pre-condition has been met, and not 252 + execute the query otherwise. For instance, we may be building a form and want a validation query to 253 + only take place when a field has been filled out. 254 + 255 + Since with Vue 3's Composition API we won't just conditionally call `useQuery` we can instead pass a 256 + reactive `pause` input to `useQuery`. 257 + 258 + In the previous example we've defined a query with mandatory arguments. The `$from` and `$limit` 259 + variables have been defined to be non-nullable `Int!` values. 260 + 261 + Let's pause the query we've just written to not execute when these variables are empty, to 262 + prevent `null` variables from being executed. We can do this by computing `pause` to become `true` 263 + whenever these variables are falsy: 264 + 265 + ```js 266 + import { reactive } from 'vue' 267 + import { useQuery } from '@urql/vue'; 268 + 269 + export default { 270 + props: ['from', 'limit'], 271 + setup({ from, limit }) { 272 + return useQuery({ 273 + query: ` 274 + query ($from: Int!, $limit: Int!) { 275 + todos(from: $from, limit: $limit) { 276 + id 277 + title 278 + } 279 + } 280 + `, 281 + variables: { from, limit }, 282 + pause: computed(() => !from.value || !limit.value) 283 + }); 284 + } 285 + }; 286 + </script> 287 + ``` 288 + 289 + Now whenever the mandatory `$from` or `$limit` variables aren't supplied the query won't be executed. 290 + This also means that `result.data` won't change, which means we'll still have access to our old data 291 + even though the variables may have changed. 292 + 293 + It's worth noting that depending on whether `from` and `limit` are reactive or not you may have to 294 + change how `pause` is computed. But there's also an imperative alternative to this API. Not only 295 + does the result you get back from `useQuery` have an `isPaused` ref, it also has `pause()` and 296 + `resume()` methods. 297 + 298 + ```jsx 299 + <template> 300 + <div v-if="fetching"> 301 + Loading... 302 + </div> 303 + <button @click="isPaused ? resume() : pause()">Toggle Query</button> 304 + </template> 305 + 306 + <script> 307 + import { useQuery } from '@urql/vue'; 308 + 309 + export default { 310 + setup() { 311 + return useQuery({ 312 + query: ` 313 + { 314 + todos { 315 + id 316 + title 317 + } 318 + } 319 + ` 320 + }); 321 + } 322 + }; 323 + </script> 324 + ``` 325 + 326 + This means that no matter whether you're in or outside of `setup()` or rather supplying the inputs 327 + to `useQuery` or using the outputs, you'll have access to ways to pause or unpause the query. 328 + 329 + ### Request Policies 330 + 331 + As has become clear in the previous sections of this page, the `useQuery` hook accepts more options 332 + than just `query` and `variables`. Another option we should touch on is `requestPolicy`. 333 + 334 + The `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By 335 + default this is set to `cache-first`, which means that we prefer to get results from our cache, but 336 + are falling back to sending an API request. 337 + 338 + In total there are four different policies that we can use: 339 + 340 + - `cache-first` (the default) prefers cached results and falls back to sending an API request when 341 + no prior result is cached. 342 + - `cache-and-network` returns cached results but also always sends an API request, which is perfect 343 + for displaying data quickly while keeping it up-to-date. 344 + - `network-only` will always send an API request and will ignore cached results. 345 + - `cache-only` will always return cached results or `null`. 346 + 347 + The `cache-and-network` policy is particularly useful, since it allows us to display data instantly 348 + if it has been cached, but also refreshes data in our cache in the background. This means though 349 + that `fetching` will be `false` for cached results although an API request may still be ongoing in 350 + the background. 351 + 352 + For this reason there's another field on results, `result.stale`, which indicates that the cached 353 + result is either outdated or that another request is being sent in the background. 354 + 355 + Request policies aren't specific to `urql`'s Vue bindings, but are a common feature in its core. [You 356 + can learn more about request policies on the API docs.](../api/core.md#requestpolicy) 357 + 358 + ### Reexecuting Queries 359 + 360 + The `useQuery` hook updates and executes queries whenever its inputs, like the `query` or 361 + `variables` change, but in some cases we may find that we need to programmatically trigger a new 362 + query. This is the purpose of the `executeQuery` method which is a method on the result object 363 + that `useQuery` returns. 364 + 365 + Triggering a query programmatically may be useful in a couple of cases. It can for instance be used 366 + to refresh data that is currently being displayed. In these cases we may also override the 367 + `requestPolicy` of our query just once and set it to `network-only` to skip the cache. 368 + 369 + ```js 370 + import { useQuery } from '@urql/vue'; 371 + 372 + export default { 373 + setup() { 374 + const result = useQuery({ 375 + query: ` 376 + { 377 + todos { 378 + id 379 + title 380 + } 381 + } 382 + ` 383 + }); 384 + 385 + return { 386 + data: result.data, 387 + fetching: result.fetching, 388 + error: result.error, 389 + refresh() { 390 + result.executeQuery({ 391 + requestPolicy: 'network-only' 392 + }); 393 + } 394 + }; 395 + } 396 + }; 397 + </script> 398 + ``` 399 + 400 + Calling `refresh` in the above example will execute the query again forcefully, and will skip the 401 + cache, since we're passing `requestPolicy: 'network-only'`. 402 + 403 + Furthermore the `executeQuery` method can also be used to programmatically start a query even 404 + when `pause` is `true`, which would usually stop all automatic queries. 405 + 406 + ### Vue Suspense 407 + 408 + In Vue 3 a [new feature was introduced](https://vuedose.tips/go-async-in-vue-3-with-suspense/) that 409 + natively allows components to suspend while data is loading, which works universally on the server 410 + and on the client, where a replacement loading template is rendered on a parent while data is 411 + loading. 412 + 413 + Any component's `setup()` function can be updated to instead be an `async setup()` function, in 414 + other words, to return a `Promise` instead of directly returning its data. This means that we can 415 + update any `setup()` function to make use of Suspense. 416 + 417 + The `useQuery`'s returned result supports this, since it is a `PromiseLike`. We can update one of 418 + our examples to have a suspending component by changing our usage of `useQuery`: 419 + 420 + ```jsx 421 + <template> 422 + <ul> 423 + <li v-for="todo in data.todos">{{ todo.title }}</li> 424 + </ul> 425 + </template> 426 + 427 + <script> 428 + import { useQuery } from '@urql/vue'; 429 + 430 + export default { 431 + async setup() { 432 + const { data, error } = await useQuery({ 433 + query: ` 434 + { 435 + todos { 436 + id 437 + title 438 + } 439 + } 440 + ` 441 + }); 442 + 443 + return { data }; 444 + } 445 + }; 446 + </script> 447 + ``` 448 + 449 + As we can see, `await useQuery(...)` here suspends the component and what we render will not have to 450 + handle the loading states of `useQuery` at all. Instead in Vue Suspense we'll have to wrap a parent 451 + component in a "Suspense boundary." This boundary is what switches a parent to a loading state while 452 + parts of its children are fetching data. The suspense promise is in essence "bubbling up" until it 453 + finds a "Suspense boundary". 454 + 455 + ``` 456 + <template> 457 + <Suspense> 458 + <template #default> 459 + <MyAsyncComponent /> 460 + </template> 461 + <template #fallback> 462 + <span>Loading...</span> 463 + </template> 464 + </Suspense> 465 + </template> 466 + ``` 467 + 468 + As long as any parent component is wrapping our component which uses `async setup()` in this 469 + boundary, we'll get Vue Suspense to work correctly and trigger this loading state. When a child 470 + suspends this component will switch to using its `#fallback` template rather than its `#default` 471 + template. 472 + 473 + ### Reading on 474 + 475 + There are some more tricks we can use with `useQuery`. [Read more about its API in the API docs for 476 + it.](../api/vue.md#usequery) 477 + 478 + ## Mutations 479 + 480 + The `useMutation` function isn't dissimilar from `useQuery` but is triggered manually and accepts 481 + only a `DocumentNode` or `string` as an input. 482 + 483 + ### Sending a mutation 484 + 485 + Let's again pick up an example with an imaginary GraphQL API for todo items, and dive into an 486 + example! We'll set up a mutation that _updates_ a todo item's title. 487 + 488 + ```js 489 + import { useMutation } from '@urql/vue'; 490 + 491 + export default { 492 + setup() { 493 + const { executeMutation: updateTodo } = useMutation(` 494 + mutation ($id: ID!, $title: String!) { 495 + updateTodo (id: $id, title: $title) { 496 + id 497 + title 498 + } 499 + } 500 + `); 501 + 502 + return { updateTodo }; 503 + }, 504 + }; 505 + ``` 506 + 507 + Similar to the `useQuery` output, `useMutation` returns a result object, which reflects the data of 508 + an executed mutation. That means it'll contain the familiar `fetching`, `error`, and `data` 509 + properties — it's identical since this is a common pattern of how `urql` 510 + presents [operation results](../api/core.md#operationresult). 511 + 512 + Unlike the `useQuery` hook, the `useMutation` hook doesn't execute automatically. At this point in 513 + our example, no mutation will be performed. To execute our mutation we instead have to call the 514 + `executeMutation` method on the result with some variables. 515 + 516 + ### Using the mutation result 517 + 518 + When calling our `updateTodo` function we have two ways of getting to the result as it comes back 519 + from our API. We can either use the result itself, since all properties related to the last 520 + [operation result](../api/core.md#operationresult) are marked as [reactive 521 + ](https://v3.vuejs.org/guide/reactivity-fundamentals.html) — or we can use the promise that the 522 + `executeMutation` method returns when it's called: 523 + 524 + ```js 525 + import { useMutation } from '@urql/vue'; 526 + 527 + export default { 528 + setup() { 529 + const updateTodoResult = useMutation(` 530 + mutation ($id: ID!, $title: String!) { 531 + updateTodo (id: $id, title: $title) { 532 + id 533 + title 534 + } 535 + } 536 + `); 537 + 538 + return { 539 + updateTodo(id, title) { 540 + const variables = { id, title: title || '' }; 541 + updateTodoResult(variables).then(result => { 542 + // The result is almost identical to `updateTodoResult` with the exception 543 + // of `result.fetching` not being set and its properties not being reactive. 544 + // It is an OperationResult. 545 + }); 546 + }, 547 + }; 548 + }, 549 + }; 550 + ``` 551 + 552 + The reactive result that `useMutation` returns is useful when your UI has to display progress or 553 + results on the mutation, and the returned promise is particularly useful when you're adding 554 + side-effects that run after the mutation has completed. 555 + 556 + ### Handling mutation errors 557 + 558 + It's worth noting that the promise we receive when calling the execute function will never 559 + reject. Instead it will always return a promise that resolves to a result. 560 + 561 + If you're checking for errors, you should use `result.error` instead, which will be set 562 + to a `CombinedError` when any kind of errors occurred while executing your mutation. 563 + [Read more about errors on our "Errors" page.](../concepts/errors.md) 564 + 565 + ```js 566 + import { useMutation } from '@urql/vue'; 567 + 568 + export default { 569 + setup() { 570 + const updateTodoResult = useMutation(` 571 + mutation ($id: ID!, $title: String!) { 572 + updateTodo (id: $id, title: $title) { 573 + id 574 + title 575 + } 576 + } 577 + `); 578 + 579 + return { 580 + updateTodo(id, title) { 581 + const variables = { id, title: title || '' }; 582 + updateTodoResult(variables).then(result => { 583 + if (result.error) { 584 + console.error('Oh no!', result.error); 585 + } 586 + }); 587 + }, 588 + }; 589 + }, 590 + }; 591 + ``` 592 + 593 + There are some more tricks we can use with `useMutation`.<br /> 594 + [Read more about its API in the API docs for it.](../api/vue.md#usemutation) 595 + 596 + ## Reading on 597 + 598 + This concludes the introduction for using `urql` with Svelte. The rest of the documentation 599 + is mostly framework-agnostic and will apply to either `urql` in general or the `@urql/core` package, 600 + which is the same between all framework bindings. Hence, next we may want to learn more about one of 601 + the following to learn more about the internals: 602 + 603 + - [How does the default "document cache" work?](../concepts/document-caching.md) 604 + - [How are errors handled and represented?](../concepts/errors.md) 605 + - [A quick overview of `urql`'s philosophy and structure.](../concepts/philosophy.md) 606 + - [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
+3 -2
docs/concepts/README.md
··· 10 10 11 11 Each page goes a little further in explaining a core concept of `urql`. 12 12 13 + - [**Document Caching**](./document-caching.md) explains the default cache mechanism of `urql`, as opposed to the opt-in 14 + [Normalized Cache](../graphcache/normalized-caching.md). 15 + - [**Errors**](./errors.md) contains information on error handling in `urql`. 13 16 - [**Philosophy**](./philosophy.md) gives a quick overview of the different aspects of GraphQL clients and `urql` in 14 17 particular, which shines a light on why you may want to use `urql`. 15 18 - [**Stream Pattern**](./stream-patterns.md) explains the inner working of `urql`, which is _stream-based_, also known as 16 19 Observable patterns in JS. 17 - - [**Core Package**](./core-package.md) defines why a shared package exists that contains the main logic of `urql`, and 18 - how we can use it directly in Node.js. 19 20 - [**Exchanges**](./exchanges.md) finally introduces _Exchanges_ and how to write extensions or addons and use them 20 21 in `urql`. 21 22
-104
docs/concepts/core-package.md
··· 1 - --- 2 - title: Core Package 3 - order: 2 4 - --- 5 - 6 - # The Core Package 7 - 8 - The `@urql/core` package contains `urql`'s `Client`, some common utilities, and some default 9 - _Exchanges_. These are the shared, default parts of `urql` that we will be using no matter which 10 - framework we're interacting with. 11 - 12 - Therefore those are also the parts of `urql` that contain its most important logic — like the 13 - [`Client`](../api/core.md#client) — and the package that we need to know about if we're either integrating `urql` with a new 14 - framework, or if we're using the "raw" `Client` in Node.js. 15 - 16 - ## Background 17 - 18 - The ["Philosophy"](./philosophy.md) page explains how `urql` solves some of problems encountered when different aspects 19 - of having a GraphQL client handle declarative querying and being a central point of extensibility. 20 - 21 - By extension there are three parts of `urql` you'll come in contact with when you add it to your 22 - app: 23 - 24 - - the framework integration that allows you to declaratively write queries and mutations in your 25 - preferred framework, which are currently the [`urql`](../api/urql.md) or 26 - [`@urql/preact`](../api/preact.md) packages 27 - - the [`Client`](../api/core.md#client) that manages the operation lifecycle and results 28 - - and, exchanges that may either be some default exchanges or some from external packages 29 - 30 - On this page we'll learn about the latter two points - shared logic that isn't specific to 31 - a particular library or framework (such as React or Preact code). 32 - 33 - _Exchanges_ are discussed in more detail on the [next page](./exchanges.md). 34 - 35 - ## Usage with Node.js 36 - 37 - The largest part of `urql` itself and the core package is the aforementioned `Client`. It's often 38 - used directly when using `urql` in Node.js without any other integration. 39 - 40 - We've previously seen how we can use the `Client`'s stream methods directly, in [Stream 41 - Patterns](./stream-patterns.md). However, the [`Client`](../api/core.md#client) also has plenty of 42 - convenience methods that make interacting with the `Client` directly a lot easier. 43 - 44 - ### One-off Queries and Mutations 45 - 46 - When you're using `urql` to send one-off queries or mutations — rather than in full framework code, 47 - where updates are important — it's common to convert the streams that we get to promises. The 48 - `client.query` and `client.mutation` methods have a shortcut to do just that. 49 - 50 - ```js 51 - const QUERY = ` 52 - query Test($id: ID!) { 53 - getUser(id: $id) { 54 - id 55 - name 56 - } 57 - } 58 - `; 59 - 60 - client 61 - .query(QUERY, { id: 'test' }) 62 - .toPromise() 63 - .then(result => { 64 - console.log(result); // { data: ... } 65 - }); 66 - ``` 67 - 68 - This may be useful when we don't plan on cancelling queries or we don't care about future updates to 69 - this data and are just looking to query a result once. 70 - 71 - Similarly there's a way to read data from the cache synchronously, provided that the cache has 72 - received a result for a given query before. The `Client` has a `readQuery` method which is a 73 - shortcut for just that. 74 - 75 - ```js 76 - const QUERY = ` 77 - query Test($id: ID!) { 78 - getUser(id: $id) { 79 - id 80 - name 81 - } 82 - } 83 - `; 84 - 85 - const result = client.readQuery(QUERY, { id: 'test' }); 86 - 87 - result; // null or { data: ... } 88 - ``` 89 - 90 - Since the streams in `urql` operate synchronously, internally this method subscribes to 91 - `client.executeQuery` and unsubscribes immediately. If a result is available in the cache it will be 92 - resolved synchronously prior to the unsubscribe. If not, the query is cancelled and no request will be sent to the GraphQL API. 93 - 94 - ## Common Utilities in Core 95 - 96 - The `@urql/core` package contains other utilities that are shared between multiple addon packages. 97 - This is a short but non-exhaustive list. It contains, 98 - 99 - - [`CombinedError`](../api/core.md#combinederror) - our abstraction to combine one or more `GraphQLError`(s) and a `NetworkError` 100 - - `makeResult` and `makeErrorResult` - utilities to create _Operation Results_ 101 - - [`createRequest`](../api/core.md#createrequest) - a utility function to create a request from a query and some variables (which 102 - generates a stable _Operation Key_) 103 - 104 - There are other utilities not mentioned here. Read more about the `@urql/core` API in the [API docs](../api/core.md).
+2 -2
docs/concepts/exchanges.md
··· 1 1 --- 2 2 title: Exchanges 3 - order: 3 3 + order: 5 4 4 --- 5 5 6 6 # Exchanges ··· 17 17 The default set of exchanges that `@urql/core` contains and applies to a `Client` are: 18 18 19 19 - `dedupExchange`: Deduplicates pending operations (pending = waiting for a result) 20 - - `cacheExchange`: The default caching logic with ["Document Caching"](../basics/document-caching.md) 20 + - `cacheExchange`: The default caching logic with ["Document Caching"](../concepts/document-caching.md) 21 21 - `fetchExchange`: Sends an operation to the API using `fetch` and adds results to the output stream 22 22 23 23 Other available exchanges:
+2 -5
docs/concepts/philosophy.md
··· 1 1 --- 2 2 title: Philosophy 3 - order: 1 3 + order: 3 4 4 --- 5 5 6 6 # Philosophy ··· 17 17 — the building blocks of `urql` — interact with one another. 18 18 19 19 ## Hello World 20 - 21 - We previously read about how to set up a `Client` in [Getting 22 - Started](../basics/getting-started.md). 23 20 24 21 When you use `urql` you will always create and set up a `Client`. There is a `createClient` 25 22 convenience helper to do just that. ··· 81 78 cache implementations; all of them allow you to prevent mixing your declarative query or mutation 82 79 code with cache-implementation details, as they mostly happen behind the scenes. 83 80 84 - We previously read about the default [Document Caching](../basics/document-caching.md). 81 + We previously read about the default [Document Caching](../concepts/document-caching.md). 85 82 86 83 Some GraphQL clients also resort to caching data in a normalized format. This is similar to 87 84 [how you may store data in Redux.](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape/)
+1 -1
docs/concepts/stream-patterns.md
··· 1 1 --- 2 2 title: Stream Patterns 3 - order: 1 3 + order: 4 4 4 --- 5 5 6 6 # Stream Patterns
+2 -2
docs/graphcache/README.md
··· 6 6 # Graphcache 7 7 8 8 In `urql`, caching is fully configurable via [_Exchanges_](../concepts/exchanges.md) and the default 9 - `cacheExchange` in `urql` offers a ["Document Cache"](../basics/document-caching.md), which is 9 + `cacheExchange` in `urql` offers a ["Document Cache"](../concepts/document-caching.md), which is 10 10 sufficient for sites that heavily rely and render 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. ··· 21 21 ## Features 22 22 23 23 The following pages introduce different features in _Graphcache_ which together make it a compelling 24 - alternative to the standard [document cache](../basics/document-caching.md) that `urql` uses by 24 + alternative to the standard [document cache](../concepts/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
+1 -1
docs/graphcache/normalized-caching.md
··· 12 12 etc is what we call "records." 13 13 14 14 Instead of storing query results as whole documents, like `urql` does with [its default "Document 15 - Caching"](../basics/document-caching.md), _Graphcache_ flattens all data it receives automatically. 15 + Caching"](../concepts/document-caching.md), _Graphcache_ flattens all data it receives automatically. 16 16 If we looked at doing this manually on the following piece of data, we'd separate each object into a 17 17 list of key-value entries per entity. 18 18
+1 -1
docs/graphcache/offline.md
··· 102 102 offline error — the `offlineExchange` won't deliver the error for this query to avoid it from being 103 103 surfaced to the user. This works particularly well in combination with ["Schema 104 104 Awareness"](./schema-awareness.md) which will deliver as much of a partial query result as possible. 105 - In combination with the [`cache-and-network` request policy](../basics/queries.md#request-policies) 105 + In combination with the [`cache-and-network` request policy](../concepts/document-caching.md#request-policies) 106 106 we can now ensure that we display as much data as possible when the user is offline while still 107 107 keeping the cache up-to-date when the user is online. 108 108
+1 -1
docs/graphcache/under-the-hood.md
··· 28 28 29 29 We've previously learned about [how to create "Optimistic Updates" in an earlier section.](./custom-updates.md#optimistic-updates) 30 30 Optimistic updates can temporarily update cached data after incoming mutations, which will trigger on screen queries to update. 31 - However, if we also use [the `cache-and-network` request policy](../basics/queries.md#request-policies) at the same time, some queries can refetch and overwrite our optimistic data, 31 + However, if we also use [the `cache-and-network` request policy](../concepts/document-caching.md#request-policies) at the same time, some queries can refetch and overwrite our optimistic data, 32 32 causing an unintended state where the intended optimistic update is destroyed. 33 33 Such an unintended refetch can also happen if after an optimistic update a query is refetched when it’s not or 34 34 only partially available in the cache.
+20
packages/site/static.config.js
··· 51 51 template: require.resolve('./src/screens/home'), 52 52 }, 53 53 { 54 + path: '/docs/concepts/core-package', 55 + redirect: 'docs/basics/core', 56 + }, 57 + { 58 + path: '/docs/basics/getting-started', 59 + redirect: 'docs/basics', 60 + }, 61 + { 62 + path: '/docs/basics/mutations', 63 + redirect: 'docs/basics', 64 + }, 65 + { 66 + path: '/docs/basics/queries', 67 + redirect: 'docs/basics', 68 + }, 69 + { 70 + path: '/docs/basics/document-caching', 71 + redirect: 'docs/concepts/document-caching', 72 + }, 73 + { 54 74 path: '404', 55 75 template: require.resolve('./src/screens/404'), 56 76 },