docs: apollo client persisted documents (#5397)

This commit is contained in:
Laurin Quast 2024-08-23 11:40:38 +02:00 committed by GitHub
parent 70a8f0aff4
commit 9eab1af44f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -59,17 +59,15 @@ flowchart LR
document request" -->C
```
## Create an App Deployment
## Extracting Persisted Documents
To create an app deployment, you need to have
[the Hive CLI installed](/docs/api-reference/cli#installation) and authenticated with your Hive
target, on which you want to deploy your app.
We need to extract the persisted documents from within our app. The method for doing this may vary
depending on the tools you are using.
In addition you must have a JSON file containing a set of persisted documents generated by a tool
such as
[GraphQL Code Generator](https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#persisted-documents).
The persisted documents must stored in a JSON file, which includes the documents along with their
corresponding hashes. This JSON file will be uploaded to the Hive Registry.
```json filename="Example: persisted-operations.json"
```json filename="persisted-operations.json"
{
"d9a00ec0c1ce": "query UsageEstimationQuery($input: UsageEstimationInput!) { __typename usageEstimation(input: $input) { __typename operations } }",
"b8d98e796421": "mutation GenerateStripeLinkMutation($selector: OrganizationSelectorInput!) { __typename generateStripePortalLink(selector: $selector) }"
@ -79,6 +77,77 @@ such as
These persisted documents define all the possible operations that your app can execute against your
GraphQL API.
As long as the app deployment using these persisted documents is active, any change of the GraphQL
API that alters the GraphQL schema as used by any of the persisted documents would break that
specific app version and therefore be an unsafe/breaking change.
<Tabs items={["GraphQL Code Generator", "Relay Compiler"]}>
<Tabs.Tab>
For GraphQL Code Generator, you can configure the client preset to generate the persisted document
manifest.
```typescript filename="codegen.ts" {9-11}
import { type CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = {
schema: 'schema.graphql',
documents: ['src/**/*.tsx'],
generates: {
'./src/gql/': {
preset: 'client',
presetConfig: {
persistedDocuments: true
}
}
}
}
```
After running the Relay Compiler, the file `persisted-documents.json` will be generated. This file
can be used for creating a new app deployment on Hive.
For more information,
[please refer to the GraphQL Code Generator documentation](https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#enable-persisted-documents).
</Tabs.Tab>
<Tabs.Tab>
For Relay Compiler, you can configure the compiler to generate the persisted document manifest.
```js filename="relay.config.js" {6-8}
module.exports = {
src: './src',
language: 'javascript',
schema: './data/schema.graphql',
excludes: ['**/node_modules/**', '**/__mocks__/**', '**/__generated__/**'],
persistConfig: {
file: './persisted-documents.json'
}
}
```
After running the Relay Compiler, the file `persisted-documents.json` will be generated. This file
can be used for creating a new app deployment on Hive.
For more information,
[please refer to the Relay documentation](https://relay.dev/docs/guides/persisted-queries/#local-persisted-queries).
</Tabs.Tab>
</Tabs>
## Create an App Deployment
To create an app deployment, you need to have
[the Hive CLI installed](/docs/api-reference/cli#installation) and authenticated with your Hive
target, on which you want to deploy your app.
The persisted documents define all the possible operations that your app can execute against your
GraphQL API.
As long as the app is using these persisted documents is active, any change of the GraphQL API that
alters the GraphQL schema as used by any of the persisted documents would break that specific app
version and therefore be an unsafe/breaking change.
@ -86,20 +155,19 @@ version and therefore be an unsafe/breaking change.
> **Note:** The GraphQL operations being uploaded must pass validation against the target schema.
> Otherwise, the app deployment creation will fail.
Once these pre-requisites are met, you can create an app deployment by running the following
command:
Once the pre-requisites are met, you can create an app deployment by running the following command.
```bash filename="Create an App Deployment via CLI"
hive app:create --name "my-app" --version "1.0.0" persisted-operations.json
hive app:create --name "my-app" --version "1.0.0" persisted-documents.json
```
The parameters `--name` and `--version` are mandatory and uniquily identify your app deployment.
| Parameter | Description |
| ------------------------ | ------------------------------------------------------------- |
| `--name` | The name of the app deployment. |
| `--version` | The version of the app deployment. |
| `persistedDocumentsFile` | The path to the JSON file containing the persisted documents. |
| Parameter | Description |
| -------------------------- | ------------------------------------------------------------- |
| `--name` | The name of the app deployment. |
| `--version` | The version of the app deployment. |
| `<persistedDocumentsFile>` | The path to the JSON file containing the persisted documents. |
An app deployment is uniquely identified by the combination of the `name` and `version` parameters
for each target.
@ -315,6 +383,10 @@ curl \
Once you have the persisted documents available on your GraphQL server or Gateway, you can send a
GraphQL request with the persisted document ID following the GraphQL over HTTP specification.
<Tabs items={["curl", "Apollo Client", "Urql", "Relay"]}>
<Tabs.Tab>
```text filename="GraphQL Request with Persisted Document"
POST /graphql
Content-Type: application/json
@ -339,6 +411,141 @@ curl \
http://localhost:4000/graphql
```
</Tabs.Tab>
<Tabs.Tab>
The code demonstrates how to send a persisted document request using Apollo Client. Make sure to
replace the placeholders with your actual values.
```typescript filename="Apollo Client Persisted Document Configuration"
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'
import { createPersistedQueryLink } from '@apollo/client/link/persisted-queries'
// replace <app_name>, <app_version>, and with your values
const appVersionPrefix = '<app_name>~<app_version>~'
const persistedQueriesLink = createPersistedQueryLink({
generateHash(document) {
// GraphQL Code Generator Client Preset generates
// the persisted document ID within the document node.
// For other implementations return the hash prefixed with the app version.
if (document?.['__metadata__']?.['hash']) {
throw Error('Hash not available for document')
}
return appVersionPrefix + document['__metadata__']['hash']
}
})
const httpLink = new HttpLink({
uri: '/graphql',
fetch(url, init) {
const parsedBody = JSON.parse(init!.body as string)
return fetch(url, {
...init,
body: JSON.stringify({
variables: parsedBody.variables,
documentId: parsedBody.extensions.persistedQuery.sha256Hash,
extensions: { ...parsedBody.extensions, persistedQuery: undefined }
})
})
}
})
const client = new ApolloClient({
cache: new InMemoryCache(),
link: persistedQueriesLink.concat(httpLink)
})
```
| Parameter | Description |
| --------------- | ---------------------------------- |
| `<app_name>` | The name of the app deployment. |
| `<app_version>` | The version of the app deployment. |
</Tabs.Tab>
<Tabs.Tab>
The code demonstrates how to send a persisted document request using Urql. Make sure to replace the
placeholders with your actual values.
```typescript filename="Urql Persisted Document Configuration"
import { createClient, fetchExchange, mapExchange } from 'urql'
// replace <app_name>, <app_version>, and with your values
const appVersionPrefix = '<app_name>~<app_version>~'
const urqlClient = createClient({
url: '/graphql',
exchanges: [
mapExchange({
onOperation(op) {
if (op.query?.['__metadata__']?.['hash']) {
throw Error('Hash not available for document')
}
return {
...op,
query: {
documentId:
// GraphQL Code Generator Client Preset generates
// the persisted document ID within the document node.
// For other implementations return the hash prefixed with the app version.
appVersionPrefix + op.query['__meta__']['hash'],
definitions: []
}
}
}
}),
fetchExchange
]
})
```
| Parameter | Description |
| --------------- | ---------------------------------- |
| `<app_name>` | The name of the app deployment. |
| `<app_version>` | The version of the app deployment. |
</Tabs.Tab>
<Tabs.Tab>
Update your Relay environment configuration to send persisted document requests instead of the
document.
```typescript filename="Relay Persisted Document Configuration"
// replace <app_name>, <app_version>, and with your values
const appVersionPrefix = '<app_name>~<app_version>~'
function fetchQuery(operation, variables) {
if (!operation.id) {
throw new Error('No persisted document hash provided.')
}
return fetch('/graphql', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
documentId: appVersionPrefix + operation.id,
variables
})
}).then(response => response.json())
}
```
| Parameter | Description |
| --------------- | ---------------------------------- |
| `<app_name>` | The name of the app deployment. |
| `<app_version>` | The version of the app deployment. |
</Tabs.Tab>
</Tabs>
## Continous Deployment (CD) Integration
We recommend integrating the app deployment creation and publishing into your CD pipeline for