Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions configs/cargo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ Represents the incoming HTTP request. It exposes nested fields such as:
- `.request.url.host` - the request host (e.g. `api.example.com`).
- `.request.url.port` - the request port (e.g. `443`).
- `.request.url.path` - the request path (e.g. `/graphql`).
- `.request.path_params` - a map of path parameters if your `graphql_endpoint` uses them. For
example, if your endpoint is `/graphql/:doc_id`, you can access the `doc_id` parameter with
`.request.path_params.doc_id`.
- `.request.operation.name` - the name of the GraphQL operation being executed, if provided.
- `.request.operation.type` - the type of GraphQL operation being executed (e.g. `"query"`,
`"mutation"`, or `"subscription"`).
Expand Down
37 changes: 37 additions & 0 deletions packages/web/docs/src/content/router/configuration/http.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,40 @@ http:
host: '127.0.0.1'
port: 8080
```

### `graphql_endpoint`

- **Type:** `string`
- **Default:** `"/graphql"`

The `graphql_endpoint` property allows you to customize the HTTP path where the GraphQL API is
exposed. By default, Hive Router serves the GraphQL API at the `/graphql` endpoint.

For example, to change the GraphQL endpoint to `/api/graphql`, you would configure it as follows:

```yaml filename="router.config.yaml"
http:
graphql_endpoint: /api/graphql
```

This configuration is useful if you want to namespace your GraphQL API under a specific path or if
you have multiple services running on the same domain and want to avoid path conflicts.

You can also use path parameters in the `graphql_endpoint` to capture dynamic segments of the URL.
This can be useful such features like Persisted Documents where the document ID can be part of the
URL path.

`path_params` will be available in the request object inside the VRL expression context for further
processing.

[Learn more about using path parameters with Persisted Documents](/docs/router/configuration/persisted_documents#using-url-path-parameters-to-provide-document-id).
[Learn more about the request object in the VRL expressions](/docs/router/configuration/expressions#request).

```yaml filename="router.config.yaml"
http:
graphql_endpoint: /graphql/:doc_id
persisted_documents:
enabled: true
spec:
expression: .request.path_params.doc_id
```
2 changes: 2 additions & 0 deletions packages/web/docs/src/content/router/configuration/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ that explains how to use that feature.
- [`supergraph`](./configuration/supergraph): Tell the router where to find your supergraph schema.
- [`traffic_shaping`](./configuration/traffic_shaping): Manage connection pooling and request
handling to subgraphs.
- [`persisted_documents`](./configuration/persisted_documents): Enable persisted documents to reduce
payload size and secure your API.
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
---
title: 'persisted_documents'
---

# persisted_documents

The `persisted_documents` configuration allows you to enable [Persisted Documents] on Hive Router
that allows you to reduce the payload size of your GraphQL requests and secure your GraphQL API by
allowing only operations that are known and trusted by your Router.

[Learn more about Persisted Documents with Hive Console](/docs/schema-registry/app-deployments#persisted-documents-on-graphql-server-and-gateway)

## Configuration Structure

The `persisted_documents` key is a top-level object in your `router.config.yaml`. It contains the
following fields:

First you need to enable persisted documents by setting the `enabled` field to `true`.

```yaml
persisted_documents:
enabled: true
```

### Source Configuration with `source`

The `source` field defines where the Router will load the persisted documents from. It supports two
sources: Hive Console CDN and a local file.

- `source`: **(object)** The source configuration for persisted documents.

#### Hive Console CDN

Then we need a way to fetch the persisted documents. The recommended way is to use Hive Console as
your persisted documents storage.

- `hive`: **(object)** The Hive Console CDN source configuration.
- `endpoint`: **(string)** The Hive Console CDN endpoint to fetch persisted documents from.
Alternatively you can set the `HIVE_CDN_ENDPOINT` environment variable.
- `key`: **(string)** The Hive Console CDN API key to authenticate requests. Alternatively you can
set the `HIVE_CDN_KEY` environment variable.

To do so, you can either use environment variables or directly set the `endpoint` and `key` fields.

```yaml {2-4} filename="router.config.yaml"
persisted_documents:
enabled: true
source:
hive:
endpoint: https://cdn.graphql-hive.com/artifacts/v1/... # Use your Hive CDN endpoint here
key: hvABCD # Use your Hive CDN API key here
```

or using environment variables:

```yaml filename="router.config.yaml"
persisted_documents:
enabled: true
```

Then set the following environment variables in your environment:

```bash
export HIVE_CDN_ENDPOINT="https://cdn.graphql-hive.com/artifacts/v1/..."
export HIVE_CDN_KEY="hvABCD"
```

#### A Persisted Documents File as Source

Alternatively, you can also load persisted documents from a local file.

- `file`: **(string)** The path to the local persisted documents JSON file.

```yaml {2-3} filename="router.config.yaml"
persisted_documents:
enabled: true
source:
file: ./persisted_documents.json # point to your local persisted documents file
```

That file must be a JSON file containing a map of document IDs to GraphQL operations, for example:

```json
{
"a1b2c3d4e5": "query GetUser($id: ID!) { user(id: $id) { id name } }",
"f6g7h8i9j0": "mutation UpdateUser($id: ID!, $name: String!) { updateUser(id: $id, name: $name) { id name } }"
}
```

### Configure Extraction of Document ID from Requests with `spec`

The `spec` field defines how the Router will extract the persisted document ID from incoming
requests. By default it is set to `hive` which expects the document ID to be provided in the body as
`documentId`.

- `spec`: **(object)** The specification for extracting document IDs from requests.
- Possible values are:
- `hive`: The default Hive specification using `documentId` in the request body.
- `apollo`: The Apollo Persisted Documents specification using
`extensions.persistedQuery.sha256Hash` in the request body.
- `relay`: The Relay specification using `doc_id` in the request body.
- `expression`: A custom specification using a user-defined expression.

#### `documentId` in Request Body (Hive / Default)

The default `hive` spec expects the persisted document ID to be provided in the request body as
`documentId`.

So the request body should look like this:

```json
{
"documentId": "my-app~my-version~a1b2c3d4e5",
"variables": {
"id": "123"
}
}
```

Then the Router will look up the operation associated with the provided `documentId` and execute it.

#### Apollo Persisted Documents Spec using `extensions.persistedQuery.sha256Hash`

There is also support for the Apollo Persisted Documents spec, which expects the document ID to be
provided in the `extensions.persistedQuery.sha256Hash` field of the request body.

To use this spec, set the `spec` field to `apollo`:

```yaml {3} filename="router.config.yaml"
persisted_documents:
enabled: true
spec: apollo
```

So the request body should look like this:

```json
{
"extensions": {
"persistedQuery": {
"version": 1,
"sha256Hash": "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"
}
}
}
```

which can be sent like this using `curl`:

```bash
curl -X POST -H 'Content-Type: application/json' http://localhost:4000/graphql \
-d '{"extensions":{"per sistedQuery":{"version":1,"sha256Hash":"ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"}}}'
```

Then the Router will look up the operation associated with the provided `sha256Hash` and execute it.

#### Relay Specification using `doc_id` in Request Body

You can also use the Relay specification, which expects the persisted document ID to be provided in
the request body as `doc_id`.

To use this spec, set the `spec` field to `relay`:

```yaml {3} filename="router.config.yaml"
persisted_documents:
enabled: true
spec: relay
```

Then the request body should look like this:

```json
{
"doc_id": "a1b2c3d4e5",
"variables": {
"id": "123"
}
}
```

Then the Router will look up the operation associated with the provided `doc_id` and execute it.

#### Custom Specification with `expression`

If none of the built-in specifications fit your needs, you can define a custom specification using
the `expression` option.

- `expression`: **(string)** A [VRL expression](./expressions) that extracts the document ID from
the incoming request.

To use a custom specification, set the `spec` field to `expression` and provide the `expression`
field:

```yaml {3-4} filename="router.config.yaml"
persisted_documents:
enabled: true
spec:
expression: .request.body.customDocumentId
```

##### Using Header to Provide Document ID

In this example, we extract the document ID from a custom header `x-document-id`.

```yaml {3-4} filename="router.config.yaml"
persisted_documents:
enabled: true
spec:
expression: .request.headers."x-document-id"
```

Then the request should include the `x-document-id` header:

```bash
curl -X POST -H 'Content-Type: application/json' -H 'x-document-id: a1b2c3d4e5' http://localhost:4000/graphql \
-d '{"variables":{"id":"123"}}'
```

##### Using a Query Parameter to Provide Document ID

In this example, we extract the document ID from a query parameter `query_id`.

```yaml {3-4} filename="router.config.yaml"
persisted_documents:
enabled: true
spec:
expression: .request.body.query_id
```

Then the request URL should include the `query_id` query parameter:

```bash
curl -X POST -H 'Content-Type: application/json' 'http://localhost:4000/graphql?query_id=a1b2c3d4e5' \
-d '{"variables":{"id":"123"}}'
```

##### Using URL Path Parameters to Provide Document ID

You can also the the request path to extract the persisted operation id. This requires you to also
customize the GraphQL endpoint.

This combination is powerful as it allows you to use the persisted operation id as it can easily be
combined with any type of HTTP proxy cache.

```yaml {3-5} filename="router.config.yaml"
http:
graphql_endpoint: /graphql/:doc_id
persisted_documents:
enabled: true
spec:
expression: .request.path_params.doc_id
```

Then the request URL should include the document ID in the path:

```bash
curl -X POST -H 'Content-Type: application/json' 'http://localhost:4000/graphql/a1b2c3d4e5' \
-d '{"variables":{"id":"123"}}'
```

### Allowing Non-Persisted Arbitrary Documents with `allow_arbitrary_operations`

After enabling persisted documents, by default the Router will reject any requests that do not
provide a valid persisted document ID.

- `allow_arbitrary_operations`: **(boolean / object)** Whether to allow arbitrary operations
alongside persisted documents. Default is `false`.

If you want to allow arbitrary operations alongside persisted documents, you can set the
`allow_arbitrary_operations` field to `true`.

```yaml {3} filename="router.config.yaml"
persisted_documents:
enabled: true
allow_arbitrary_operations: true
```

#### Conditional Allowance with `expression`

Alternatively, you can conditionally allow arbitrary operations based on a user-defined expression.

- `expression`: **(string)** A [VRL expression](./expressions) that evaluates to a boolean value to
determine whether to allow arbitrary operations.

To use a conditional allowance, set the `allow_arbitrary_operations` field to an object with the
`expression` field:

```yaml {3-4} filename="router.config.yaml"
persisted_documents:
enabled: true
allow_arbitrary_operations:
expression: .request.headers."x-allow-arbitrary" == "true"
```

Then the Router will evaluate the provided expression for each request. If it evaluates to `true`,
the Router will allow arbitrary operations; otherwise, it will enforce persisted documents only.

In the example above, you can allow arbitrary operations by including the `x-allow-arbitrary: true`
header in your request:

```bash
curl -X POST -H 'Content-Type: application/json' -H 'x-allow-arbitrary: true' http://localhost:4000/graphql \
-d '{"query":"query { user(id: \"123\") { id name } }"}'
```
Loading
Loading