Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1---
2title: Svelte Bindings
3order: 2
4---
5
6# Svelte
7
8## Getting started
9
10This "Getting Started" guide covers how to install and set up `urql` and provide a `Client` for
11Svelte. The `@urql/svelte` package, which provides bindings for Svelte, doesn't fundamentally
12function differently from `@urql/preact` or `urql` and uses the same [Core Package and
13`Client`](./core.md).
14
15### Installation
16
17Installing `@urql/svelte` is quick and no other packages are immediately necessary.
18
19```sh
20yarn add @urql/svelte
21# or
22npm install --save @urql/svelte
23```
24
25Most libraries related to GraphQL also need the `graphql` package to be installed as a peer
26dependency, so that they can adapt to your specific versioning requirements. That's why we'll need
27to install `graphql` alongside `@urql/svelte`.
28
29Both the `@urql/svelte` and `graphql` packages follow [semantic versioning](https://semver.org) and
30all `@urql/svelte` packages will define a range of compatible versions of `graphql`. Watch out
31for 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
34Note: if using Vite as your bundler, you might stumble upon the error `Function called outside component initialization`, which will prevent the page from loading. To fix it, you must add `@urql/svelte` to Vite's configuration property [`optimizeDeps.exclude`](https://vitejs.dev/config/#dep-optimization-options):
35
36```js
37{
38 optimizeDeps: {
39 exclude: ['@urql/svelte'],
40 }
41 // other properties
42}
43```
44
45### Setting up the `Client`
46
47The `@urql/svelte` package exports a `Client` class, which we can use to create
48the GraphQL client. This central `Client` manages all of our GraphQL requests and results.
49
50```js
51import { Client, cacheExchange, fetchExchange } from '@urql/svelte';
52
53const client = new Client({
54 url: 'http://localhost:3000/graphql',
55 exchanges: [cacheExchange, fetchExchange],
56});
57```
58
59At the bare minimum we'll need to pass an API's `url` and `exchanges`
60when we create a `Client` to get started.
61
62Another common option is `fetchOptions`. This option allows us to customize the options that will be
63passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or
64a function returning an options object.
65
66In the following example we'll add a token to each `fetch` request that our `Client` sends to our
67GraphQL API.
68
69```js
70const client = new Client({
71 url: 'http://localhost:3000/graphql',
72 exchanges: [cacheExchange, fetchExchange],
73 fetchOptions: () => {
74 const token = getToken();
75 return {
76 headers: { authorization: token ? `Bearer ${token}` : '' },
77 };
78 },
79});
80```
81
82### Providing the `Client`
83
84To make use of the `Client` in Svelte we will have to provide it via the
85[Context API](https://svelte.dev/tutorial/context-api). From a parent component to its child
86components. This will share one `Client` with the rest of our app, if we for instance provide the
87`Client`
88
89```html
90<script>
91 import { Client, setContextClient, cacheExchange, fetchExchange } from '@urql/svelte';
92
93 const client = new Client({
94 url: 'http://localhost:3000/graphql',
95 exchanges: [cacheExchange, fetchExchange],
96 });
97
98 setContextClient(client);
99</script>
100```
101
102The `setContextClient` method internally calls [Svelte's `setContext`
103function](https://svelte.dev/docs#run-time-svelte-setcontext). The `@urql/svelte` package also exposes a `getContextClient`
104function that uses [`getContext`](https://svelte.dev/docs#run-time-svelte-getcontext) to retrieve the `Client` in
105child components. This is used to input the client into `@urql/svelte`'s API.
106
107## Queries
108
109We'll implement queries using the `queryStore` function from `@urql/svelte`.
110
111The `queryStore` function creates a [Svelte Writable store](https://svelte.dev/docs#writable).
112You can use it to initialise a data container in `urql`. This store holds on to our query inputs,
113like the GraphQL query and variables, which we can change to launch new queries. It also exposes
114the query's eventual result, which we can then observe.
115
116### Run a first query
117
118For the following examples, we'll imagine that we're querying data from a GraphQL API that contains
119todo items. Let's dive right into it!
120
121```js
122<script>
123 import { queryStore, gql, getContextClient } from '@urql/svelte';
124
125 const todos = queryStore({
126 client: getContextClient(),
127 query: gql`
128 query {
129 todos {
130 id
131 title
132 }
133 }
134 `,
135 });
136</script>
137
138{#if $todos.fetching}
139<p>Loading...</p>
140{:else if $todos.error}
141<p>Oh no... {$todos.error.message}</p>
142{:else}
143<ul>
144 {#each $todos.data.todos as todo}
145 <li>{todo.title}</li>
146 {/each}
147</ul>
148{/if}
149```
150
151Here we have implemented our first GraphQL query to fetch todos. We're first creating a
152`queryStore` which will start our GraphQL query.
153
154The `todos` store can now be used like any other Svelte store using a
155[reactive auto-subscription](https://svelte.dev/tutorial/auto-subscriptions) in Svelte. This means
156that we prefix `$todos` with a dollar symbol, which automatically subscribes us to its changes.
157
158### Variables
159
160Typically we'll also need to pass variables to our queries, for instance, if we are dealing with
161pagination. For this purpose the `queryStore` also accepts a `variables` argument, which we can
162use to supply variables to our query.
163
164```js
165<script>
166 import { queryStore, getContextClient, gql } from '@urql/svelte';
167
168 $: todos = queryStore({
169 client: getContextClient(),
170 query: gql`
171 query ($from: Int!, $limit: Int!) {
172 todos(from: $from, limit: $limit) {
173 id
174 title
175 }
176 }
177 `,
178 variables: { from, limit }
179 });
180</script>
181...
182```
183
184> Note that we prefix the variable with `$` so Svelte knows that this store is reactive
185
186As 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
189The `queryStore` also supports being actively changed. This will hook into Svelte's reactivity
190model as well and cause the `query` utility to start a new operation.
191
192```js
193<script>
194 import { queryStore, getContextClient, gql } from '@urql/svelte';
195
196 let limit = 10;
197 let from = 0;
198 $: todos = queryStore({
199 client: getContextClient(),
200 query: gql`
201 query ($from: Int!, $limit: Int!) {
202 todos(from: $from, limit: $limit) {
203 id
204 title
205 }
206 }
207 `,
208 variables: { from, limit }
209 );
210
211 function nextPage() {
212 from = from + 10
213 }
214</script>
215
216<button on:click={nextPage}>Next page<button></button></button>
217```
218
219### Pausing Queries
220
221In some cases we may want our queries to not execute until a pre-condition has been met. Since the
222`query` operation exists for the entire component lifecycle however, it can't just be stopped and
223started at will. Instead, the `queryStore` accepts a key named `pause` that will tell the store that
224is starts out as paused.
225
226For instance, we may start out with a paused store and then unpause it once a callback is invoked:
227
228```html
229<script>
230 import { queryStore, gql, getContextClient } from '@urql/svelte';
231
232 $: todos = queryStore({
233 client: getContextClient(),
234 query: gql`
235 query {
236 todos {
237 id
238 title
239 }
240 }
241 `,
242 pause: true,
243 });
244
245 function unpause() {
246 todos.resume();
247 }
248</script>
249
250<button on:click="{unpause}">Unpause</button>
251```
252
253### Request Policies
254
255The `queryStore` also accepts another key apart from `query` and `variables`. Optionally
256you may pass a `requestPolicy`.
257
258The `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By
259default, this is set to `cache-first`, which means that we prefer to get results from our cache, but
260are falling back to sending an API request.
261
262Request policies aren't specific to `urql`'s Svelte bindings, but are a common feature in its core.
263[You can learn more about how the cache behaves given the four different policies on the "Document
264Caching" page.](../basics/document-caching.md)
265
266```js
267<script>
268 import { queryStore, gql, getContextClient } from '@urql/svelte';
269
270 $: todos = queryStore({
271 client: getContextClient(),
272 query: gql`
273 query {
274 todos {
275 id
276 title
277 }
278 }
279 `,
280 requestPolicy: 'cache-and-network'
281 });
282</script>
283
284...
285```
286
287As we can see, the `requestPolicy` is easily changed by passing it directly as a "context option"
288when creating a `queryStore`.
289
290Internally, the `requestPolicy` is just one of several "**context** options". The `context`
291provides metadata apart from the usual `query` and `variables` we may pass. This means that
292we may also change the `Client`'s default `requestPolicy` by passing it there.
293
294```js
295import { Client, cacheExchange, fetchExchange } from '@urql/svelte';
296
297const client = new Client({
298 url: 'http://localhost:3000/graphql',
299 exchanges: [cacheExchange, fetchExchange],
300 // every operation will by default use cache-and-network rather
301 // than cache-first now:
302 requestPolicy: 'cache-and-network',
303});
304```
305
306### Context Options
307
308As mentioned, the `requestPolicy` option that we're passing to the `queryStore` is a part of
309`urql`'s context options. In fact, there are several more built-in context options, and the
310`requestPolicy` option is one of them. Another option we've already seen is the `url` option, which
311determines our API's URL.
312
313```js
314<script>
315 import { queryStore, gql, getContextClient } from '@urql/svelte';
316
317 $: todos = queryStore({
318 client: getContextClient(),
319 query: gql`
320 query {
321 todos {
322 id
323 title
324 }
325 }
326 `,
327 context: { url: 'http://localhost:3000/graphql?debug=true', }
328 });
329</script>
330
331...
332```
333
334As we can see, the `context` argument for `queryStore` accepts any known `context` option and
335can be used to alter them per query rather than globally. The `Client` accepts a subset of `context`
336options, while the `queryStore` argument does the same for a single query. They're then merged
337for your operation and form a full `Context` object for each operation, which means that any given
338query is able to override them as needed.
339
340[You can find a list of all `Context` options in the API docs.](../api/core.md#operationcontext)
341
342### Reexecuting queries
343
344Sometimes we'll need to arbitrarly reexecute a query to check for new data on the server, this can be done through:
345
346```jsx
347<script>
348 import { queryStore, gql, getContextClient } from '@urql/svelte';
349
350 const client = getContextClient();
351 const query = gql`
352 query {
353 todos {
354 id
355 title
356 }
357 }
358 `
359 $: todos = queryStore({
360 client,
361 query,
362 });
363
364 function refresh() {
365 todos.reexecute({
366 requestPolicy: 'network-only'
367 });
368 }
369</script>
370```
371
372We use the `requestPolicy` with value `network-only` so we don't hit our cache and dispatch a refresh,
373if it updates the data the `todos` will be updated due to our cache updating.
374
375### Reading on
376
377There are some more tricks we can use with `queryStore`.
378[Read more about its API in the API docs for it.](../api/svelte.md#queryStore)
379
380## Mutations
381
382The `mutationStore` function is similar to the `queryStore` function but is triggered manually and
383can accept a [`GraphQLRequest` object](../api/core.md#graphqlrequest).
384
385### Sending a mutation
386
387Let's again pick up an example with an imaginary GraphQL API for todo items, and dive into an
388example! We'll set up a mutation that _updates_ a todo item's title.
389
390```html
391<script>
392 import { mutationStore, gql, getContextClient } from '@urql/svelte';
393
394 export let id;
395
396 let result;
397 let client = getContextClient();
398 const updateTodo = ({ id, title }) => {
399 result = mutationStore({
400 client,
401 query: gql`
402 mutation ($id: ID!, $title: String!) {
403 updateTodo(id: $id, title: $title) {
404 id
405 title
406 }
407 }
408 `,
409 variables: { id, title },
410 });
411 };
412</script>
413```
414
415This small call to `mutationStore` accepts a `query` property (besides the `variables` property) and
416returns the `OperationResult` as a store.
417
418Unlike the `query` function, we don't want the mutation to start automatically hence we enclose it in
419a function. The `result` will be updated with the `fetching`, `data`, ... as a normal query would which
420you can in-turn use in your UI.
421
422### Handling mutation errors
423
424It's worth noting that the promise we receive when calling the execute function will never
425reject. Instead it will always return a promise that resolves to an `mutationStore`, even if the
426mutation has failed.
427
428If you're checking for errors, you should use `mutationStore.error` instead, which will be set
429to a `CombinedError` when any kind of errors occurred while executing your mutation.
430[Read more about errors on our "Errors" page.](./errors.md)
431
432```jsx
433mutateTodo({ id, title: newTitle }).then(result => {
434 if (result.error) {
435 console.error('Oh no!', result.error);
436 }
437});
438```
439
440## Reading on
441
442This concludes the introduction for using `urql` with Svelte. The rest of the documentation
443is mostly framework-agnostic and will apply to either `urql` in general, or the `@urql/core` package,
444which is the same between all framework bindings. Hence, next we may want to learn more about one of
445the following to learn more about the internals:
446
447- [How does the default "document cache" work?](./document-caching.md)
448- [How are errors handled and represented?](./errors.md)
449- [A quick overview of `urql`'s architecture and structure.](../architecture.md)
450- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)