Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Request Batching Appendix #308

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
166 changes: 166 additions & 0 deletions spec/Appendix C - Request Batching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
## C. Appendix: Request Batching

This appendix defines an optional extension to the GraphQL-over-HTTP protocol that allows for the batching of multiple GraphQL requests within a single HTTP request.

:: **Request batching** enables a client to execute multiple GraphQL operations within a single HTTP request. This reduces the number of HTTP requests required when performing multiple independent operations, thus improving network efficiency and reducing overhead.

For instance, it is not possible to execute both a query and a mutation within the same GraphQL request.

```graphql
query {
shoppingCart {
...shoppingCartRepsonse
}
}

mutation($id: ID!) {
addToWishlist(productId: $id) {
...wishlistResponse
}
}
```

Request batching allows a single HTTP request to include multiple GraphQL requests. Each request can specify its own query document, variables, operation name and extensions. This approach is particularly useful for GraphQL gateways to execute multiple independent operations concurrently, reducing network overhead and improving performance by consolidating multiple operations into a single HTTP request.

### Batching Request

A server MAY accept a **batching request** via `POST`.

#### Batching Request Format

A _well-formed batching request_ is a JSON-encoded list of maps. Typically each map is expected to be a well-formed _GraphQL-over-HTTP request_, although
the exact format of each map is not defined by this appendix. As such, any alternative JSON-encoded formats supported by the server, such as the format
defined in Appendix A: Persisted Documents, may be processed as part of the batching request.

For example, this is a typical request:

```json
[
{
"query": "{ categories { id name } }"
},
{
"query": "query ($id: ID!) { product(id: $id) { id name } }",
"variables": {
"id": "2"
}
}
]
```

This also is a _well-formed batching request_, as it is a JSON-encoded list of maps:

```json
[
{
"invalid": "request"
}
]
```

However, this is not a _well-formed batching request_, as the list contains an entry which is not a map:

```json
[
"sample"
]
```

### POST

A **batching request** instructs the server to perform multiple operations concurrently. The request MUST have a body
that conforms to the _well-formed batching request_ format listed above encoded in the `application/json` media type, or another media type supported by the server.

A client MUST indicate the media type of a request body using the `Content-Type` header as specified in [RFC7231](https://datatracker.ietf.org/doc/html/rfc7231).

A server MUST support POST requests encoded with the `application/json` media type (as outlined in the GraphQL-over-HTTP specification).

If the client does not supply a `Content-Type` header with a POST request, the server SHOULD reject the request using the appropriate `4xx` status code.

The server MUST support JSON media types in the `Accept` header in the same manner that is defined by the GraphQL-over-HTTP specification (i.e. `application/json`
and `application/graphql-response+json`.

The server MUST respond with a _well-formed batching response_ format, defined below, OR refuse the entire _batching request_ with a well-formed _GraphQL response_ and
a 4xx status code (such as when the request fails authentication).

### Execution

Each operation within a _well-formed batching request_ is executed as an _independent operation_
constituting its own GraphQL-over-HTTP request. Each _independent operation_ SHOULD execute concurrently
on the server. Each _independent operation_ MUST return a well-formed _GraphQL response_, whether or not
errors are encountered during the processing of the request.

For instance, the above request for `categories` and `product` may produce these responses:

```json
{
"data": {
"categories": [
{ "id": "1", "name": "Chairs" }
]
}
}
```

and

```json
{
"data": {
"product": { "id": "50", "name": "High-back chair" }
}
}
```

And the above `invalid` request may produce this response:

```json
{
"errors": [
{ "message": "Query is required." },
{ "message": "Key 'invalid' is unknown." }
]
}
```

### Batching Response Format

A _well-formed batching response_ MUST return a JSON-encoded list of well-formed _GraphQL responses_ which correspond to the requests,
and MUST appear in the same order. Any HTTP status codes generated by the _individual operations_ MUST be discarded.

A _well-formed batching response_ MUST return a 200 status code.

A _well-formed batching response_ MUST respond with a supported JSON content type within the `Content-Type` header; see the GraphQL-over-HTTP
specification for details. Typically this will be `application/json` or `application/graphql-response+json` depending on the `Accept` header and other factors.

For example, the sample responses above would generate this _well-formed batching response_:

```json
[
{
"data": {
"categories": [
{ "id": "1", "name": "Chairs" }
]
}
},
{
"data": {
"product": { "id": "50", "name": "High-back chair" }
}
}
]
```

and

```json
[
{
"errors": [
{ "message": "Query is required." },
{ "message": "Key 'invalid' is unknown." }
]
}
]
```
Loading