Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1--- 2title: Persistence & Uploads 3order: 1 4--- 5 6# Persisted Queries and Uploads 7 8`urql` supports (Automatic) Persisted Queries, and File Uploads via GraphQL 9Multipart requests. For persisted queries to work, some setup work is needed, 10while File Upload support is built into `@urql/core@4`. 11 12## Automatic Persisted Queries 13 14Persisted Queries allow us to send requests to the GraphQL API that can easily be cached on the fly, 15both by the GraphQL API itself and potential CDN caching layers. This is based on the unofficial 16[GraphQL Persisted Queries 17Spec](https://github.com/apollographql/apollo-link-persisted-queries#apollo-engine). 18 19With Automatic Persisted Queries the client hashes the GraphQL query and turns it into an SHA256 20hash and sends this hash instead of the full query. If the server has seen this GraphQL query before 21it will recognise it by its hash and process the GraphQL API request as usual, otherwise it may 22respond using a `PersistedQueryNotFound` error. In that case the client is supposed to instead send 23the full GraphQL query, and the hash together, which will cause the query to be "registered" with the 24server. 25 26Additionally, we could also decide to send these hashed queries as GET requests instead of POST 27requests. If we only send the persisted queries with hashes as GET requests then they become a lot 28easier for a CDN to cache, as by default most caches would not cache POST requests automatically. 29 30In `urql`, we may use the `@urql/exchange-persisted` package's `persistedExchange` to 31enable support for Automatic Persisted Queries. This exchange works alongside other fetch or 32subscription exchanges by adding metadata for persisted queries to each GraphQL 33request by modifying the `extensions` object of operations. 34 35> **Note:** [You can find a code example for `@urql/exchange-persisted` in an example in the `urql` repository.](https://github.com/urql-graphql/urql/tree/main/examples/with-apq) 36 37### Installation & Setup 38 39First install `@urql/exchange-persisted` alongside `urql`: 40 41```sh 42yarn add @urql/exchange-persisted 43# or 44npm install --save @urql/exchange-persisted 45``` 46 47You'll then need to add the `persistedExchange` function, that this package exposes, 48to your `exchanges`, in front of exchanges that communicate with the API: 49 50```js 51import { Client, fetchExchange, cacheExchange } from 'urql'; 52import { persistedExchange } from '@urql/exchange-persisted'; 53 54const client = new Client({ 55 url: 'http://localhost:1234/graphql', 56 exchanges: [ 57 cacheExchange, 58 persistedExchange({ 59 preferGetForPersistedQueries: true, 60 }), 61 fetchExchange, 62 ], 63}); 64``` 65 66As we can see, typically it's recommended to set `preferGetForPersistedQueries` to `true` 67to encourage persisted queries to use GET requests instead of POST so that CDNs can do their job. 68When set to `true` or `'within-url-limit'`, persisted queries will use GET requests if the 69resulting URL doesn't exceed the 2048 character limit. 70 71The `fetchExchange` can see the modifications that the `persistedExchange` is 72making to operations, and understands to leave out the `query` from any request 73as needed. The same should be happening to the `subscriptionExchange`, if you're 74using it for queries. 75 76### Customizing Hashing 77 78The `persistedExchange` also accepts a `generateHash` option. This may be used to swap out the 79exchange's default method of generating SHA256 hashes. By default, the exchange will use the 80built-in [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) when it's 81available, and in Node.js it'll use the [Node Crypto Module](https://nodejs.org/api/crypto.html) 82instead. 83 84If you're using [the `graphql-persisted-document-loader` for 85Webpack](https://github.com/leoasis/graphql-persisted-document-loader), for instance, then you will 86already have a loader generating SHA256 hashes for you at compile time. In that case we could swap 87out the `generateHash` function with a much simpler one that uses the `generateHash` function's 88second argument, a GraphQL `DocumentNode` object. 89 90```js 91persistedExchange({ 92 generateHash: (_, document) => document.documentId, 93}); 94``` 95 96If you're using **React Native** then you may not have access to the Web Crypto API, which means 97that you have to provide your own SHA256 function to the `persistedExchange`. Luckily, we can do 98so easily by using the first argument `generateHash` receives, a GraphQL query as a string. 99 100```js 101import sha256 from 'hash.js/lib/hash/sha/256'; 102 103persistedExchange({ 104 async generateHash(query) { 105 return sha256().update(query).digest('hex'); 106 }, 107}); 108``` 109 110Additionally, if the API only expects persisted queries and not arbitrary ones and all queries are 111pre-registered against the API then the `persistedExchange` may be put into a **non-automatic** 112persisted queries mode by giving it the `enforcePersistedQueries: true` option. This disables any 113retry logic and assumes that persisted queries will be handled like regular GraphQL requests. 114 115## File Uploads 116 117GraphQL server APIs commonly support the [GraphQL Multipart Request 118spec](https://github.com/jaydenseric/graphql-multipart-request-spec) to allow for File Uploads 119directly with a GraphQL API. 120 121If a GraphQL API supports this, we can pass a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) 122or a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) directly into our variables and 123define the corresponding scalar for our variable, which is often called `File` or `Upload`. 124 125In a browser, the `File` object may often be retrieved via a 126[file input](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications), 127for example. 128 129> **Note:** If you are using your own version of `File` and `Blob` ensure you are properly extending the 130> so it can be properly identified as a file. 131 132The `@urql/core@4` package supports File Uploads natively, so we won't have to do any installation 133or setup work. When `urql` sees a `File` or a `Blob` anywhere in your `variables`, it switches to 134a `multipart/form-data` request, converts the request to a `FormData` object, according to the 135GraphQL Multipart Request specification, and sends it off to the API. 136 137> **Note:** Previously, this worked by installing the `@urql/multipart-fetch-exchange` package. 138> however, this package has been deprecated and file uploads are now built into `@urql/core@4`. 139 140[You can find a code example for file uploads in an example in the `urql` repository.](https://github.com/urql-graphql/urql/tree/main/examples/with-multipart)