diff --git a/packages/web/docs/src/pages/docs/features/app-deployments.mdx b/packages/web/docs/src/pages/docs/features/app-deployments.mdx index c1f200275..59a5d6567 100644 --- a/packages/web/docs/src/pages/docs/features/app-deployments.mdx +++ b/packages/web/docs/src/pages/docs/features/app-deployments.mdx @@ -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. + + + + + +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). + + + + + +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). + + + + + +## 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. | +| `` | 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. + + + + ```text filename="GraphQL Request with Persisted Document" POST /graphql Content-Type: application/json @@ -339,6 +411,141 @@ curl \ http://localhost:4000/graphql ``` + + + + +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 , , and with your values +const appVersionPrefix = '~~' + +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 | +| --------------- | ---------------------------------- | +| `` | The name of the app deployment. | +| `` | The version of the app deployment. | + + + + + +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 , , and with your values +const appVersionPrefix = '~~' + +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 | +| --------------- | ---------------------------------- | +| `` | The name of the app deployment. | +| `` | The version of the app deployment. | + + + + + +Update your Relay environment configuration to send persisted document requests instead of the +document. + +```typescript filename="Relay Persisted Document Configuration" +// replace , , and with your values +const appVersionPrefix = '~~' + +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 | +| --------------- | ---------------------------------- | +| `` | The name of the app deployment. | +| `` | The version of the app deployment. | + + + + + ## Continous Deployment (CD) Integration We recommend integrating the app deployment creation and publishing into your CD pipeline for