From de74b1a1de3d5ffeb4e5e597269fbd9662ec0623 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 19:23:06 +0200 Subject: [PATCH 01/22] Add Appendix A -- application/json responses --- spec/Appendix A -- application-json.md | 161 ++++++++++++++++++++++ spec/GraphQLOverHTTP.md | 181 ++----------------------- 2 files changed, 170 insertions(+), 172 deletions(-) create mode 100644 spec/Appendix A -- application-json.md diff --git a/spec/Appendix A -- application-json.md b/spec/Appendix A -- application-json.md new file mode 100644 index 00000000..c34b7135 --- /dev/null +++ b/spec/Appendix A -- application-json.md @@ -0,0 +1,161 @@ +# A. Appendix: `application/json` responses + +Previous to this specification, the article +[Serving over HTTP](https://graphql.org/learn/serving-over-http) +([WayBack Machine entry, 1st June 2022](https://web.archive.org/web/20220601155421/https://graphql.org/learn/serving-over-http)) +on the graphql.org website served as guidance. + +This article used `application/json` as media type for the response. + +In some cases, the response received by a client may not originate from a +GraphQL service, but instead from an intermediary—such as an API gateway, proxy, +firewall or other middleware—that does not implement this specification. Such an +intermediary might produce the response to indicate an error, returning a +response with `4xx` or `5xx` status code and potentially using the standard +`application/json` media type to encode the reason for the error. Such a +response is unlikely to be a valid GraphQL response. + +For this reason, a client application receiving an `application/json` response, +could rely on the response being a well-formed _GraphQL response_ only if the +status code is `200`. + +This caused multiple observability issues because it was challenging to +distinguish a well-formed _GraphQL response_ from an intermediary response. + +`application/graphql-response+json` allows to distringuish a well-formed +_GraphQL response_ from another intermediary response and is the required media +type moving forward. + +For compatibility reasons, clients and servers may support `application/json` as +described in this section. + +Note: Servers may wish to only support the `application/graphql-response+json` +media type so that related HTTP tooling may utilize the HTTP status codes of +responses without having to be GraphQL-aware. + +### Accept + +To maximize compatibility, a client may include the media type +`application/json` in the `Accept` header. When doing this, it is recommended +that the client set the `Accept` header to +`application/graphql-response+json, application/json;q=0.9`. + +Note: The `q=0.9` parameter tells content negotiation that `application/json` +should only be used if `application/graphql-response+json` is not supported. + +### Status codes + +When using the `application/json` media type, the server should use the `200` +status code for every response to a well-formed _GraphQL-over-HTTP request_, +independent of any _GraphQL request error_ or _GraphQL field error_ raised. + +If the response uses a non-`200` status code then the client must not rely on +the body to be a well-formed _GraphQL response_. + +Note: A status code in the `4xx` or `5xx` ranges or status code `203` (and maybe +others) could originate from an intermediary; since the client cannot determine +if an `application/json` response with arbitrary status code is a well-formed +_GraphQL response_ (because it cannot trust the source) the server must use +`200` status code to guarantee to the client that the response has not been +generated or modified by an intermediary. See +[processing a response](#sec-Processing-a-response) for more details. + +If the _GraphQL response_ contains a non-null {data} entry then the server must +use the `200` status code. + +Note: This indicates that no _GraphQL request error_ was raised, though one or +more _GraphQL field error_ may have been raised this is still a successful +execution - see "partial response" in the GraphQL specification. + +The server should not use a `4xx` or `5xx` status code for a response to a +well-formed _GraphQL-over-HTTP request_. + +Note: For compatibility with legacy servers, this specification allows the use +of `4xx` or `5xx` status codes for a failed well-formed _GraphQL-over-HTTP +request_ where the response uses the `application/json` media type, but it is +strongly discouraged. To use `4xx` and `5xx` status codes in these situations, +please use the `application/graphql-response+json` media type. + +If the URL is not used for other purposes, the server should use a `4xx` status +code to respond to a request that is not a well-formed _GraphQL-over-HTTP +request_. + +Note: For compatibility with legacy servers, this specification allows the use +of `2xx` or `5xx` status codes when responding to invalid requests using the +`application/json` media type, but it is strongly discouraged. + +Note: URLs that enable GraphQL requests may enable other types of requests - see +the [URL](#url) section. + +#### Examples + +The following examples provide guidance on how to deal with specific error cases +when using the `application/json` media type to encode the response body: + +##### JSON parsing failure + +For example a POST request body of `NONSENSE` or `{"query":` (note: invalid +JSON). + +Requests that the server cannot interpret SHOULD result in status code `400` +(Bad Request). + +##### Invalid parameters + +For example a POST request body of `{"qeury": "{__typename}"}` (note: typo) or +`{"query": "query Q ($i:Int!) { q(i: $i) }", "variables": [7]}` (note: invalid +shape for `variables`). + +A request that does not constitute a well-formed _GraphQL-over-HTTP request_ +SHOULD result in status code `400` (Bad Request). + +##### Document parsing failure + +For example a POST request body of `{"query": "{"}`. + +Requests where the _GraphQL document_ cannot be parsed SHOULD result in status +code `200` (Okay). + +##### Document validation failure + +If a request fails to pass _GraphQL validation_, the server SHOULD NOT execute +the request and SHOULD return a status code of `200` (Okay). + +##### Operation cannot be determined + +If [GetOperation()]() raises a +_GraphQL request error_, the server SHOULD NOT execute the request and SHOULD +return a status code of `200` (Okay). + +##### Variable coercion failure + +If +[CoerceVariableValues()]() +raises a _GraphQL request error_, the server SHOULD NOT execute the request and +SHOULD return a status code of `200` (Okay). + +For example the well-formed GraphQL-over-HTTP request: + +```json +{ + "query": "query getItemName($id: ID!) { item(id: $id) { id name } }", + "variables": { "id": null } +} +``` + +would fail variable coercion as the value for `id` would fail to satisfy the +query document's expectation that `id` is non-null. + +##### Field errors encountered during execution + +If the operation is executed and no _GraphQL request error_ is raised then the +server SHOULD respond with a status code of `200` (Okay). This is the case even +if a _GraphQL field error_ is raised during +[GraphQL's ExecuteQuery()]() or +[GraphQL's ExecuteMutation()](). + + diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index acdf5ebb..3c7c9cf5 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -24,14 +24,6 @@ The [GraphQL specification](https://spec.graphql.org) deliberately does not specify the transport layer; however, HTTP is the most common choice when serving GraphQL to remote clients due to its ubiquity. -Previous to this specification, the article -[Serving over HTTP](https://graphql.org/learn/serving-over-http) -([WayBack Machine entry, 1st June 2022](https://web.archive.org/web/20220601155421/https://graphql.org/learn/serving-over-http)) -on the graphql.org website served as guidance, and leading implementations on -both client and server have mostly upheld those best practices and thus -established a de-facto standard that is commonly used throughout the ecosystem. -This specification aims to codify and expand on this work. - **Copyright notice** Copyright © 2022-present, GraphQL contributors @@ -174,19 +166,12 @@ throughout this specification. ## Media Types -The following are the officially recognized GraphQL media types to designate -using the JSON encoding for GraphQL requests: - -| Name | Description | -| ------------------ | --------------------------------------- | -| `application/json` | Standard type for GraphQL JSON requests | - -And for a _GraphQL response_: +The following are the officially recognized GraphQL media types: -| Name | Description | -| ----------------------------------- | ------------------------------------------------------------------ | -| `application/graphql-response+json` | The preferred type for server responses; better HTTP compatibility | -| `application/json` | An alternative type for responses (to support legacy clients) | +| Name | Description | +| ----------------------------------- | ------------------------------------- | +| `application/json` | Media type for GraphQL JSON requests | +| `application/graphql-response+json` | Media type for GraphQL JSON responses | For details of the shapes of these JSON payloads, please see [Request](#sec-Request) and [Response](#sec-Response). @@ -515,153 +500,9 @@ execution regardless of validation errors. ## Status Codes In case of errors that completely prevent the generation of a well-formed -_GraphQL response_, the server SHOULD respond with the appropriate status code +_GraphQL response_, the server MUST respond with the appropriate status code depending on the concrete error condition, and MUST NOT respond with a `2xx` -status code when using the `application/graphql-response+json` media type. - -Note: This rule is "should" to maintain compatibility with legacy servers which -can return 200 status codes even when this type of error occurs, but only when -not using the `application/graphql-response+json` media type. - -Otherwise, the status codes depends on the media type with which the GraphQL -response will be served: - -### application/json - -This section only applies when the response body is to use the -`application/json` media type. - -The server SHOULD use the `200` status code for every response to a well-formed -_GraphQL-over-HTTP request_, independent of any _GraphQL request error_ or -_GraphQL field error_ raised. - -If the response uses a non-`200` status code then the client MUST NOT rely on -the body to be a well-formed _GraphQL response_. - -Note: A status code in the `4xx` or `5xx` ranges or status code `203` (and maybe -others) could originate from an intermediary; since the client cannot determine -if an `application/json` response with arbitrary status code is a well-formed -_GraphQL response_ (because it cannot trust the source) the server must use -`200` status code to guarantee to the client that the response has not been -generated or modified by an intermediary. See -[processing a response](#sec-Processing-a-response) for more details. - -If the _GraphQL response_ contains a non-null {data} entry then the server MUST -use the `200` status code. - -Note: This indicates that no _GraphQL request error_ was raised, though one or -more _GraphQL field error_ may have been raised this is still a successful -execution - see "partial response" in the GraphQL specification. - -The server SHOULD NOT use a `4xx` or `5xx` status code for a response to a -well-formed _GraphQL-over-HTTP request_. - -Note: For compatibility with legacy servers, this specification allows the use -of `4xx` or `5xx` status codes for a failed well-formed _GraphQL-over-HTTP -request_ where the response uses the `application/json` media type, but it is -strongly discouraged. To use `4xx` and `5xx` status codes in these situations, -please use the `application/graphql-response+json` media type. - -If the URL is not used for other purposes, the server SHOULD use a `4xx` status -code to respond to a request that is not a well-formed _GraphQL-over-HTTP -request_. - -Note: For compatibility with legacy servers, this specification allows the use -of `2xx` or `5xx` status codes when responding to invalid requests using the -`application/json` media type, but it is strongly discouraged. - -Note: URLs that enable GraphQL requests may enable other types of requests - see -the [URL](#url) section. - -#### Examples - -The following examples provide guidance on how to deal with specific error cases -when using the `application/json` media type to encode the response body: - -##### JSON parsing failure - -For example a POST request body of `NONSENSE` or `{"query":` (note: invalid -JSON). - -Requests that the server cannot interpret SHOULD result in status code `400` -(Bad Request). - -##### Invalid parameters - -For example a POST request body of `{"qeury": "{__typename}"}` (note: typo) or -`{"query": "query Q ($i:Int!) { q(i: $i) }", "variables": [7]}` (note: invalid -shape for `variables`). - -A request that does not constitute a well-formed _GraphQL-over-HTTP request_ -SHOULD result in status code `400` (Bad Request). - -##### Document parsing failure - -For example a POST request body of `{"query": "{"}`. - -Requests where the _GraphQL document_ cannot be parsed SHOULD result in status -code `200` (Okay). - -##### Document validation failure - -If a request fails to pass _GraphQL validation_, the server SHOULD NOT execute -the request and SHOULD return a status code of `200` (Okay). - -##### Operation cannot be determined - -If [GetOperation()]() raises a -_GraphQL request error_, the server SHOULD NOT execute the request and SHOULD -return a status code of `200` (Okay). - -##### Variable coercion failure - -If -[CoerceVariableValues()]() -raises a _GraphQL request error_, the server SHOULD NOT execute the request and -SHOULD return a status code of `200` (Okay). - -For example the well-formed GraphQL-over-HTTP request: - -```json -{ - "query": "query getItemName($id: ID!) { item(id: $id) { id name } }", - "variables": { "id": null } -} -``` - -would fail variable coercion as the value for `id` would fail to satisfy the -query document's expectation that `id` is non-null. - -##### Field errors encountered during execution - -If the operation is executed and no _GraphQL request error_ is raised then the -server SHOULD respond with a status code of `200` (Okay). This is the case even -if a _GraphQL field error_ is raised during -[GraphQL's ExecuteQuery()]() or -[GraphQL's ExecuteMutation()](). - - - -### application/graphql-response+json - -This section only applies when the response body uses the -`application/graphql-response+json` media type. - -With this media type, clients should process the response as a well-formed -_GraphQL response_ independent of the HTTP status code, and should read the -response body (specifically {data} and {errors}) to determine the status of the -response. - -Note: The purpose of setting a status code is to aid intermediary services and -tooling (which may not implement this specification) in understanding the rough -status of a response. This is useful in request logs, anomaly and intrusion -detection, metrics and observability, API gateways, and more. The status code is -not intended to aid the client, in fact it is recommended the client ignore the -status code when this media type is in use. +status code. If the _GraphQL response_ contains the {data} entry and it is not {null}, then the server MUST reply with a `2xx` status code. @@ -727,12 +568,6 @@ Note: The GraphQL specification indicates that the only situation in which the _GraphQL response_ does not include the {data} entry is one in which the {errors} entry is populated. -Note: When the response media type is `application/graphql-response+json`, -clients can rely on the response being a well-formed _GraphQL response_ -regardless of the status code. Intermediary servers may use the status code to -determine the status of the _GraphQL response_ without needing to process the -response body. - #### Examples The following examples provide guidance on how to deal with specific error cases @@ -922,3 +757,5 @@ conflicts with future versions of this specification as ongoing development aims to standardize and ensure the security and interoperability of GraphQL over HTTP whilst accounting for its growing feature set. For this reason, it is recommended to adhere to the officially recognized formats outlined here. + +# [Appendix: application/json](Appendix%20A%20--%20application-json.md) From 06e8a91b1ade80903bce18f5b3f81813319a31a8 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 19:29:27 +0200 Subject: [PATCH 02/22] typo --- spec/Appendix A -- application-json.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/Appendix A -- application-json.md b/spec/Appendix A -- application-json.md index c34b7135..9d10a142 100644 --- a/spec/Appendix A -- application-json.md +++ b/spec/Appendix A -- application-json.md @@ -22,7 +22,7 @@ status code is `200`. This caused multiple observability issues because it was challenging to distinguish a well-formed _GraphQL response_ from an intermediary response. -`application/graphql-response+json` allows to distringuish a well-formed +`application/graphql-response+json` allows to distinguish a well-formed _GraphQL response_ from another intermediary response and is the required media type moving forward. From 08092ef7711f3d9b59df52765ef47e4d979160fe Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 19:30:52 +0200 Subject: [PATCH 03/22] format --- spec/Appendix A -- application-json.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/Appendix A -- application-json.md b/spec/Appendix A -- application-json.md index 9d10a142..e7be1bf4 100644 --- a/spec/Appendix A -- application-json.md +++ b/spec/Appendix A -- application-json.md @@ -22,9 +22,9 @@ status code is `200`. This caused multiple observability issues because it was challenging to distinguish a well-formed _GraphQL response_ from an intermediary response. -`application/graphql-response+json` allows to distinguish a well-formed -_GraphQL response_ from another intermediary response and is the required media -type moving forward. +`application/graphql-response+json` allows to distinguish a well-formed _GraphQL +response_ from another intermediary response and is the required media type +moving forward. For compatibility reasons, clients and servers may support `application/json` as described in this section. From 365a486c4106475b5f6ab09259f1b858ef259733 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Fri, 3 Apr 2026 11:57:20 +0200 Subject: [PATCH 04/22] Keep diff small --- spec/GraphQLOverHTTP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 3c7c9cf5..901ce169 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -500,7 +500,7 @@ execution regardless of validation errors. ## Status Codes In case of errors that completely prevent the generation of a well-formed -_GraphQL response_, the server MUST respond with the appropriate status code +_GraphQL response_, the server SHOULD respond with the appropriate status code depending on the concrete error condition, and MUST NOT respond with a `2xx` status code. From 7ee84ee7162ce4d0d4ca64731f4e25af85763cdc Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Fri, 3 Apr 2026 22:59:19 +0200 Subject: [PATCH 05/22] State that a server must support `application/graphql-response+json` --- spec/GraphQLOverHTTP.md | 55 ++--------------------------------------- 1 file changed, 2 insertions(+), 53 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 901ce169..fa2aaf4e 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -239,21 +239,6 @@ client gets something useful, it needs to indicate the media types it supports. The client MUST include the media type `application/graphql-response+json` in the `Accept` header. -If the client knows that the server supports -`application/graphql-response+json`, it is RECOMMENDED that the client set the -`Accept` header to `application/graphql-response+json`. Otherwise, to maximize -compatibility the client SHOULD include the media type `application/json` in the -`Accept` header and it is RECOMMENDED that the client set the `Accept` header to -`application/graphql-response+json, application/json;q=0.9`. - -Note: The `q=0.9` parameter tells content negotiation that `application/json` -should only be used if `application/graphql-response+json` is not supported. - -The `application/graphql-response+json` media type adds improved support for -HTTP status codes compared to the legacy `application/json` media type. When -accepting both media types, the client SHOULD indicate it prefers -`application/graphql-response+json` over `application/json`. - ## GET For HTTP GET requests, the _GraphQL-over-HTTP request_ parameters MUST be @@ -453,27 +438,8 @@ For maximal compatibility, a _server_ SHOULD support using both the `application/json` and the `application/graphql-response+json` media types for responses. -Each newly created or updated GraphQL _server_ SHOULD support responses using -the `application/graphql-response+json` media type. - -:: A _legacy server_ is a _server_ that does not support responses using the -`application/graphql-response+json` media type. - -Note: Prior to this specification, the media type `application/json` was in wide -use for the HTTP response payload type. Unfortunately this means clients cannot -trust responses from the server that do not use an HTTP 2xx status code (since -these replies may come from non-compliant HTTP servers or proxies somewhere in -the request chain). For this reason, this specification introduces the -`application/graphql-response+json` media type on responses; however support for -this new media type is optional to allow legacy servers time to transition. - -A server MAY choose to not support the `application/json` response media type, -however doing so may limit compatibility with existing clients, so it is only -recommended when creating a new GraphQL service. - -Note: Servers may wish to enforce that clients use the -`application/graphql-response+json` data type so that related HTTP tooling may -utilize the HTTP status codes of responses without having to be GraphQL-aware. +A GraphQL server MUST support responses using the +application/graphql-response+json media type. ## Validation @@ -640,23 +606,6 @@ response; it still indicates successful execution. This section of the specification is non-normative, even where the words and phrases specified in RFC2119 are used. -## Processing a response - -In some cases, the response received by a client may not originate from a -GraphQL service, but instead from an intermediary—such as an API gateway, proxy, -firewall or other middleware—that does not implement this specification. Such an -intermediary might produce the response to indicate an error, returning a -response with `4xx` or `5xx` status code and potentially using the standard -`application/json` media type to encode the reason for the error. Such a -response is unlikely to be a valid GraphQL response. - -For this reason, a client application can rely on the response being a -well-formed _GraphQL response_ only if at least one of the following conditions -is met: - -- the response media type is `application/graphql-response+json`, or -- the status code is `200`. - ## Partial success The result of executing a GraphQL operation may contain partial data as well as From 5fcc6ca40076e35489e0e91ccddc2ddbe4f0edfb Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Fri, 3 Apr 2026 23:06:30 +0200 Subject: [PATCH 06/22] Format, link to Appendix A --- spec/GraphQLOverHTTP.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index fa2aaf4e..437a5477 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -431,15 +431,15 @@ one of the media types it has requested, hence `406 Not Acceptable` being the recommended response. However, the server authors may know better about the specific clients consuming their endpoint, thus both approaches are permitted. -A server MUST support responses using at least one of the official GraphQL -response media types. +A GraphQL server MUST support responses using the +application/graphql-response+json media type. For maximal compatibility, a _server_ SHOULD support using both the `application/json` and the `application/graphql-response+json` media types for responses. -A GraphQL server MUST support responses using the -application/graphql-response+json media type. +Note: See [Appendix A](#sec-Appendix-application-json-responses) for more +details about `application/json` responses. ## Validation From eba7cf7883ac7792c37c496fe58fd7526e830596 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Fri, 3 Apr 2026 23:08:05 +0200 Subject: [PATCH 07/22] add missing quotes --- spec/GraphQLOverHTTP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 437a5477..999142e6 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -432,7 +432,7 @@ recommended response. However, the server authors may know better about the specific clients consuming their endpoint, thus both approaches are permitted. A GraphQL server MUST support responses using the -application/graphql-response+json media type. +`application/graphql-response+json` media type. For maximal compatibility, a _server_ SHOULD support using both the `application/json` and the `application/graphql-response+json` media types for From 44c3b9d99321f64d8e5f1f01bcc3ee2569ba14c1 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 23 Apr 2026 14:41:10 +0200 Subject: [PATCH 08/22] Add a SHOULD for clients to support both media types, symmetrical to the server wording --- spec/GraphQLOverHTTP.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 999142e6..cf52b210 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -239,6 +239,14 @@ client gets something useful, it needs to indicate the media types it supports. The client MUST include the media type `application/graphql-response+json` in the `Accept` header. +For maximal compatibility, a _client_ SHOULD support receiving both +`application/json` and the `application/graphql-response+json` responses. When +doing this, it is recommended that the client set the `Accept` header to +`application/graphql-response+json, application/json;q=0.9`. + +Note: See [Appendix A](#sec-Appendix-application-json-responses) for more +details about `application/json` responses. + ## GET For HTTP GET requests, the _GraphQL-over-HTTP request_ parameters MUST be From fa09bb939e5339c244be3c3219e370bebde16ecd Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Tue, 5 May 2026 11:56:07 +0200 Subject: [PATCH 09/22] Reword the client compatibility paragraph --- spec/GraphQLOverHTTP.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index cf52b210..e9b817bd 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -239,12 +239,11 @@ client gets something useful, it needs to indicate the media types it supports. The client MUST include the media type `application/graphql-response+json` in the `Accept` header. -For maximal compatibility, a _client_ SHOULD support receiving both -`application/json` and the `application/graphql-response+json` responses. When -doing this, it is recommended that the client set the `Accept` header to -`application/graphql-response+json, application/json;q=0.9`. +If the client doesn't know that the server supports +`application/graphql-response+json`, it is RECOMMENDED that the client set the +`Accept` header to `application/graphql-response+json, application/json;q=0.9`. -Note: See [Appendix A](#sec-Appendix-application-json-responses) for more +See [Appendix A](#sec-Appendix-application-json-responses) for more details about `application/json` responses. ## GET From 9e8e5370a6533fe6d6dc33c3c35120f1fa0283aa Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Tue, 5 May 2026 11:57:16 +0200 Subject: [PATCH 10/22] format --- spec/GraphQLOverHTTP.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index e9b817bd..bed5d8e1 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -243,8 +243,8 @@ If the client doesn't know that the server supports `application/graphql-response+json`, it is RECOMMENDED that the client set the `Accept` header to `application/graphql-response+json, application/json;q=0.9`. -See [Appendix A](#sec-Appendix-application-json-responses) for more -details about `application/json` responses. +See [Appendix A](#sec-Appendix-application-json-responses) for more details +about `application/json` responses. ## GET From 1d6869d728df337d5bc0e053c6e8604e29bea49e Mon Sep 17 00:00:00 2001 From: Benjie Date: Thu, 7 May 2026 15:17:06 +0100 Subject: [PATCH 11/22] Restore important guidance, improve legacy support (#398) * Restore important guidance and recommend support for Accept:application/json * Reword sentence to make the exclusion clear * Clarify another paragraph * Clarify * Non-normative recommendation of application/json for successful legacy requests * Legacy can use any 2xx status code * Consistent order * Trim extraneous text --- spec/Appendix A -- application-json.md | 90 ++++++++++++++------------ spec/GraphQLOverHTTP.md | 82 +++++++++++++++++------ 2 files changed, 111 insertions(+), 61 deletions(-) diff --git a/spec/Appendix A -- application-json.md b/spec/Appendix A -- application-json.md index e7be1bf4..06feb3cd 100644 --- a/spec/Appendix A -- application-json.md +++ b/spec/Appendix A -- application-json.md @@ -1,11 +1,13 @@ # A. Appendix: `application/json` responses +This section only applies when the response body uses or may use the legacy +`application/json` media type for compatibility reasons. + Previous to this specification, the article [Serving over HTTP](https://graphql.org/learn/serving-over-http) ([WayBack Machine entry, 1st June 2022](https://web.archive.org/web/20220601155421/https://graphql.org/learn/serving-over-http)) -on the graphql.org website served as guidance. - -This article used `application/json` as media type for the response. +on the graphql.org website served as guidance. This article used +`application/json` as media type for the response. In some cases, the response received by a client may not originate from a GraphQL service, but instead from an intermediary—such as an API gateway, proxy, @@ -15,41 +17,43 @@ response with `4xx` or `5xx` status code and potentially using the standard `application/json` media type to encode the reason for the error. Such a response is unlikely to be a valid GraphQL response. -For this reason, a client application receiving an `application/json` response, -could rely on the response being a well-formed _GraphQL response_ only if the -status code is `200`. - -This caused multiple observability issues because it was challenging to -distinguish a well-formed _GraphQL response_ from an intermediary response. - -`application/graphql-response+json` allows to distinguish a well-formed _GraphQL -response_ from another intermediary response and is the required media type -moving forward. - -For compatibility reasons, clients and servers may support `application/json` as -described in this section. - -Note: Servers may wish to only support the `application/graphql-response+json` -media type so that related HTTP tooling may utilize the HTTP status codes of -responses without having to be GraphQL-aware. - -### Accept - -To maximize compatibility, a client may include the media type -`application/json` in the `Accept` header. When doing this, it is recommended -that the client set the `Accept` header to +For this reason, a client receiving an `application/json` response can only rely +on the response being a well-formed _GraphQL response_ if the status code is +`200`. However, responding to all GraphQL requests with HTTP 200 means that +intermediary observability software cannot determine the status of the request +without processing the response body. + +Responding with the `application/graphql-response+json` media type enables the +client to distinguish a well-formed _GraphQL response_ from an intermediary +response, and is required by both clients and servers under this specification. +This appendix exists to increase interoperability with legacy clients/servers +that have not yet adopted this specification. + +Note: Servers may wish to respond to `Accept: application/json` requests with +the `application/graphql-response+json` media type so that related HTTP tooling +may utilize the HTTP status codes of responses without having to be +GraphQL-aware. Doing so may impact error-handling behavior of legacy clients, +and may prevent legacy clients from processing responses if they require the +response `Content-Type` to be `application/json`. + +## Accept + +To enable compatibility with legacy servers, the client SHOULD include the media +type `application/json` in the `Accept` header and it is RECOMMENDED that such a +client set the `Accept` header to `application/graphql-response+json, application/json;q=0.9`. Note: The `q=0.9` parameter tells content negotiation that `application/json` should only be used if `application/graphql-response+json` is not supported. -### Status codes +## Status codes -When using the `application/json` media type, the server should use the `200` -status code for every response to a well-formed _GraphQL-over-HTTP request_, -independent of any _GraphQL request error_ or _GraphQL field error_ raised. +When responding with the legacy `application/json` media type, the server SHOULD +use the `200` status code for every response to a well-formed _GraphQL-over-HTTP +request_ independent of any _GraphQL request error_ or _GraphQL field error_ +raised. -If the response uses a non-`200` status code then the client must not rely on +If the response uses a non-`2xx` status code then the client MUST NOT rely on the body to be a well-formed _GraphQL response_. Note: A status code in the `4xx` or `5xx` ranges or status code `203` (and maybe @@ -60,14 +64,14 @@ _GraphQL response_ (because it cannot trust the source) the server must use generated or modified by an intermediary. See [processing a response](#sec-Processing-a-response) for more details. -If the _GraphQL response_ contains a non-null {data} entry then the server must -use the `200` status code. +If the _GraphQL response_ contains a non-null {data} entry then the server MUST +use a `2xx` status code and SHOULD use the `200` status code. Note: This indicates that no _GraphQL request error_ was raised, though one or more _GraphQL field error_ may have been raised this is still a successful execution - see "partial response" in the GraphQL specification. -The server should not use a `4xx` or `5xx` status code for a response to a +The server SHOULD NOT use a `4xx` or `5xx` status code for a response to a well-formed _GraphQL-over-HTTP request_. Note: For compatibility with legacy servers, this specification allows the use @@ -76,7 +80,7 @@ request_ where the response uses the `application/json` media type, but it is strongly discouraged. To use `4xx` and `5xx` status codes in these situations, please use the `application/graphql-response+json` media type. -If the URL is not used for other purposes, the server should use a `4xx` status +If the URL is not used for other purposes, the server SHOULD use a `4xx` status code to respond to a request that is not a well-formed _GraphQL-over-HTTP request_. @@ -87,12 +91,12 @@ of `2xx` or `5xx` status codes when responding to invalid requests using the Note: URLs that enable GraphQL requests may enable other types of requests - see the [URL](#url) section. -#### Examples +### Examples The following examples provide guidance on how to deal with specific error cases when using the `application/json` media type to encode the response body: -##### JSON parsing failure +#### JSON parsing failure For example a POST request body of `NONSENSE` or `{"query":` (note: invalid JSON). @@ -100,7 +104,7 @@ JSON). Requests that the server cannot interpret SHOULD result in status code `400` (Bad Request). -##### Invalid parameters +#### Invalid parameters For example a POST request body of `{"qeury": "{__typename}"}` (note: typo) or `{"query": "query Q ($i:Int!) { q(i: $i) }", "variables": [7]}` (note: invalid @@ -109,25 +113,25 @@ shape for `variables`). A request that does not constitute a well-formed _GraphQL-over-HTTP request_ SHOULD result in status code `400` (Bad Request). -##### Document parsing failure +#### Document parsing failure For example a POST request body of `{"query": "{"}`. Requests where the _GraphQL document_ cannot be parsed SHOULD result in status code `200` (Okay). -##### Document validation failure +#### Document validation failure If a request fails to pass _GraphQL validation_, the server SHOULD NOT execute the request and SHOULD return a status code of `200` (Okay). -##### Operation cannot be determined +#### Operation cannot be determined If [GetOperation()]() raises a _GraphQL request error_, the server SHOULD NOT execute the request and SHOULD return a status code of `200` (Okay). -##### Variable coercion failure +#### Variable coercion failure If [CoerceVariableValues()]() @@ -146,7 +150,7 @@ For example the well-formed GraphQL-over-HTTP request: would fail variable coercion as the value for `id` would fail to satisfy the query document's expectation that `id` is non-null. -##### Field errors encountered during execution +#### Field errors encountered during execution If the operation is executed and no _GraphQL request error_ is raised then the server SHOULD respond with a status code of `200` (Okay). This is the case even diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index bed5d8e1..1cf65edc 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -239,11 +239,14 @@ client gets something useful, it needs to indicate the media types it supports. The client MUST include the media type `application/graphql-response+json` in the `Accept` header. +:: A _legacy client_ is a client that does not support responses using the +`application/graphql-response+json` media type, and thus does not conform to +this specification. + If the client doesn't know that the server supports `application/graphql-response+json`, it is RECOMMENDED that the client set the -`Accept` header to `application/graphql-response+json, application/json;q=0.9`. - -See [Appendix A](#sec-Appendix-application-json-responses) for more details +`Accept` header to `application/graphql-response+json, application/json;q=0.9`; +see [Appendix A](#sec-Appendix-application-json-responses) for more details about `application/json` responses. ## GET @@ -419,6 +422,13 @@ A server MUST indicate the media type of the response with a `Content-Type` header, and SHOULD indicate the encoding (e.g. `application/graphql-response+json; charset=utf-8`). +A server MUST support responses using the `application/graphql-response+json` +media type. + +:: A _legacy server_ is a server that does not support responses using the +`application/graphql-response+json` media type, and thus does not conform to +this specification. + If an `Accept` header is provided, the server MUST respect the given `Accept` header and attempt to encode the response in the highest priority media type listed that is supported by the server. @@ -429,25 +439,39 @@ specification, when a client does not include at least one supported media type in the `Accept` HTTP header, the server MUST either: 1. Respond with a `406 Not Acceptable` status code and stop processing the - request (RECOMMENDED); OR -2. Disregard the `Accept` header and respond with the server's choice of media - type (NOT RECOMMENDED). + request; OR. +1. Disregard the `Accept` header and respond with the server's choice of media + type. + +If the `Accept` header does not indicate support for one of the server's +preferred media types but does indicate support for `application/json`, to +improve compatibility with _legacy client_ it is RECOMMENDED that the server +either: + +1. Respond with the `application/json` media type as detailed in + [Appendix A](#sec-Appendix-application-json-responses); OR +1. Disregard the `Accept` header and respond with the + `application/graphql-response+json` media type. + +Note: Responding to such a request with the `application/json` media type only +if it contains non-null {data} (and thus would produce HTTP `2xx` under both +`application/json` and `application/graphql-response+json` media types) allows +for richer status codes for unsuccessful requests whilst maximizing +compatibility with _legacy client_ for successful and partially successful +requests. A response with the `application/json` media type could originate from +non-GraphQL intermediary servers and middlewares handling failures (HTTP `4xx` +and `5xx`), so clients can typically only rely on an `application/json` response +to be from GraphQL when it uses HTTP `2xx` status code. + +If the `Accept` header is present but indicates support for neither any of the +server's supported media types nor `application/json`, it is RECOMMENDED to +respond with `406 Not Acceptable`. Note: It is unlikely that a client can process a response that does not match one of the media types it has requested, hence `406 Not Acceptable` being the recommended response. However, the server authors may know better about the specific clients consuming their endpoint, thus both approaches are permitted. -A GraphQL server MUST support responses using the -`application/graphql-response+json` media type. - -For maximal compatibility, a _server_ SHOULD support using both the -`application/json` and the `application/graphql-response+json` media types for -responses. - -Note: See [Appendix A](#sec-Appendix-application-json-responses) for more -details about `application/json` responses. - ## Validation Validation of a well-formed _GraphQL-over-HTTP request_ SHOULD apply all the @@ -474,8 +498,30 @@ execution regardless of validation errors. In case of errors that completely prevent the generation of a well-formed _GraphQL response_, the server SHOULD respond with the appropriate status code -depending on the concrete error condition, and MUST NOT respond with a `2xx` -status code. +depending on the concrete error condition. + +Otherwise, the status code to use depends on the media type with which the +GraphQL response will be served. + +For legacy `application/json` responses, see +[Appendix A](#sec-Appendix-application-json-responses). + +### application/graphql-response+json + +This section only applies when the response body uses the +`application/graphql-response+json` media type. + +Clients should process the response as a well-formed _GraphQL response_ +independent of the HTTP status code. + +Note: With `application/graphql-response+json`, clients know the response is +well formed and should determine the detailed status of the response from the +response body alone, allowing server authors to adopt more appropriate status +codes without impacting behavior of existing clients. Intermediary servers may +use the status code to determine the status of the _GraphQL response_ without +needing to process the response body; this is useful in request logs, developer +tooling, anomaly and intrusion detection, metrics and observability, API +gateways, and more. If the _GraphQL response_ contains the {data} entry and it is not {null}, then the server MUST reply with a `2xx` status code. From 5bfb54cfce149a4cd403e365ac26a04da1f35085 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 23 Jun 2026 13:22:39 +0100 Subject: [PATCH 12/22] No need for this rule, and it forbids persisted docs --- spec/GraphQLOverHTTP.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 1cf65edc..6c95e452 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -115,9 +115,6 @@ A _server_ MUST enable GraphQL requests to one or more GraphQL schemas. Each GraphQL schema a _server_ provides MUST be served via one or more URLs. -A _server_ MUST NOT require the _client_ to use different URLs for different -GraphQL query and mutation requests to the same GraphQL schema. - The GraphQL schema available via a single URL MAY be different for different clients. For example, alpha testers or authenticated users may have access to a schema with additional fields. From fd807c3422c6785ec02b3939f98a8b3a508c8e05 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 23 Jun 2026 13:23:41 +0100 Subject: [PATCH 13/22] 'GraphQL POST request' defined, doesn't feel right --- spec/GraphQLOverHTTP.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 6c95e452..b229c926 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -304,8 +304,8 @@ http://example.com/graphql?query=query(%24id%3A%20ID!)%7Buser(id%3A%24id)%7Bname ## POST -A GraphQL POST request instructs the server to perform a query or mutation -operation. A GraphQL POST request MUST have a body which contains values of the +A POST request instructs the GraphQL-over-HTTP server to perform a query or +mutation operation. The request MUST have a body which contains values of the _GraphQL-over-HTTP request_ parameters encoded in one of the officially recognized GraphQL media types, or another media type supported by the server. From 1c479e08a9c7998b7895233cde132b87aedc96e9 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 23 Jun 2026 13:23:52 +0100 Subject: [PATCH 14/22] Consistency with prior text --- spec/GraphQLOverHTTP.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index b229c926..d204cee0 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -546,6 +546,8 @@ reply with an appropriate `4xx` or `5xx` status code: - If the failure is due to an issue in the request itself, the appropriate `4xx` status code should be used: + - If a mutation is attempted via the `GET` verb, status code `405` MUST be + used. - If an unsupported HTTP method is used, status code `405` is RECOMMENDED. - If the `Content-Type` of the request is not supported, status code `415` is RECOMMENDED. From e9976a41a273f940158739ca7e0821fdf86e07c8 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 23 Jun 2026 13:24:03 +0100 Subject: [PATCH 15/22] No need to reference the appendix --- spec/GraphQLOverHTTP.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index d204cee0..6fb7b356 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -240,11 +240,9 @@ the `Accept` header. `application/graphql-response+json` media type, and thus does not conform to this specification. -If the client doesn't know that the server supports -`application/graphql-response+json`, it is RECOMMENDED that the client set the -`Accept` header to `application/graphql-response+json, application/json;q=0.9`; -see [Appendix A](#sec-Appendix-application-json-responses) for more details -about `application/json` responses. +If if is not known that the server supports `application/graphql-response+json`, +it is RECOMMENDED that the client set the `Accept` header to +`application/graphql-response+json, application/json;q=0.9`. ## GET From 32d57b7f0790a8dbceaea7e2dcf44a3c1ca6d2f5 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 23 Jun 2026 13:49:43 +0100 Subject: [PATCH 16/22] Remove dependency on Appendix A --- spec/GraphQLOverHTTP.md | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 6fb7b356..26c1a643 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -438,25 +438,19 @@ in the `Accept` HTTP header, the server MUST either: 1. Disregard the `Accept` header and respond with the server's choice of media type. -If the `Accept` header does not indicate support for one of the server's -preferred media types but does indicate support for `application/json`, to -improve compatibility with _legacy client_ it is RECOMMENDED that the server -either: - -1. Respond with the `application/json` media type as detailed in - [Appendix A](#sec-Appendix-application-json-responses); OR -1. Disregard the `Accept` header and respond with the - `application/graphql-response+json` media type. - -Note: Responding to such a request with the `application/json` media type only -if it contains non-null {data} (and thus would produce HTTP `2xx` under both -`application/json` and `application/graphql-response+json` media types) allows -for richer status codes for unsuccessful requests whilst maximizing -compatibility with _legacy client_ for successful and partially successful -requests. A response with the `application/json` media type could originate from -non-GraphQL intermediary servers and middlewares handling failures (HTTP `4xx` -and `5xx`), so clients can typically only rely on an `application/json` response -to be from GraphQL when it uses HTTP `2xx` status code. +To improve compatibility with _legacy client_, if the `Accept` header does not +indicate support for one of the server's preferred media types but does indicate +support for `application/json`, it is RECOMMENDED to perform the request as if +it had `Accept: application/graphql-response+json` but use +`Content-Type: application/json` for any response with a `2xx` status code. + +Note: This recommendation uses this specification's full range of HTTP status +codes whilst maximizing compatibility with _legacy client_ for successful and +partially successful requests. HTTP responses could originate from non-GraphQL +intermediary servers and middlewares handling failures (HTTP `4xx` and `5xx`), +so clients typically can only rely on a response to be from GraphQL either when +it is successful (HTTP `2xx`) or when it explicitly declares it is a GraphQL +response (`Content-Type: application/graphql-response+json`). If the `Accept` header is present but indicates support for neither any of the server's supported media types nor `application/json`, it is RECOMMENDED to From ebc4d9b135bcf45c09324adb45c89dc15f9640bf Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 23 Jun 2026 14:07:40 +0100 Subject: [PATCH 17/22] Remove Appendix A and perform additional editorial --- spec/Appendix A -- application-json.md | 165 ------------------------- spec/GraphQLOverHTTP.md | 54 ++++---- 2 files changed, 21 insertions(+), 198 deletions(-) delete mode 100644 spec/Appendix A -- application-json.md diff --git a/spec/Appendix A -- application-json.md b/spec/Appendix A -- application-json.md deleted file mode 100644 index 06feb3cd..00000000 --- a/spec/Appendix A -- application-json.md +++ /dev/null @@ -1,165 +0,0 @@ -# A. Appendix: `application/json` responses - -This section only applies when the response body uses or may use the legacy -`application/json` media type for compatibility reasons. - -Previous to this specification, the article -[Serving over HTTP](https://graphql.org/learn/serving-over-http) -([WayBack Machine entry, 1st June 2022](https://web.archive.org/web/20220601155421/https://graphql.org/learn/serving-over-http)) -on the graphql.org website served as guidance. This article used -`application/json` as media type for the response. - -In some cases, the response received by a client may not originate from a -GraphQL service, but instead from an intermediary—such as an API gateway, proxy, -firewall or other middleware—that does not implement this specification. Such an -intermediary might produce the response to indicate an error, returning a -response with `4xx` or `5xx` status code and potentially using the standard -`application/json` media type to encode the reason for the error. Such a -response is unlikely to be a valid GraphQL response. - -For this reason, a client receiving an `application/json` response can only rely -on the response being a well-formed _GraphQL response_ if the status code is -`200`. However, responding to all GraphQL requests with HTTP 200 means that -intermediary observability software cannot determine the status of the request -without processing the response body. - -Responding with the `application/graphql-response+json` media type enables the -client to distinguish a well-formed _GraphQL response_ from an intermediary -response, and is required by both clients and servers under this specification. -This appendix exists to increase interoperability with legacy clients/servers -that have not yet adopted this specification. - -Note: Servers may wish to respond to `Accept: application/json` requests with -the `application/graphql-response+json` media type so that related HTTP tooling -may utilize the HTTP status codes of responses without having to be -GraphQL-aware. Doing so may impact error-handling behavior of legacy clients, -and may prevent legacy clients from processing responses if they require the -response `Content-Type` to be `application/json`. - -## Accept - -To enable compatibility with legacy servers, the client SHOULD include the media -type `application/json` in the `Accept` header and it is RECOMMENDED that such a -client set the `Accept` header to -`application/graphql-response+json, application/json;q=0.9`. - -Note: The `q=0.9` parameter tells content negotiation that `application/json` -should only be used if `application/graphql-response+json` is not supported. - -## Status codes - -When responding with the legacy `application/json` media type, the server SHOULD -use the `200` status code for every response to a well-formed _GraphQL-over-HTTP -request_ independent of any _GraphQL request error_ or _GraphQL field error_ -raised. - -If the response uses a non-`2xx` status code then the client MUST NOT rely on -the body to be a well-formed _GraphQL response_. - -Note: A status code in the `4xx` or `5xx` ranges or status code `203` (and maybe -others) could originate from an intermediary; since the client cannot determine -if an `application/json` response with arbitrary status code is a well-formed -_GraphQL response_ (because it cannot trust the source) the server must use -`200` status code to guarantee to the client that the response has not been -generated or modified by an intermediary. See -[processing a response](#sec-Processing-a-response) for more details. - -If the _GraphQL response_ contains a non-null {data} entry then the server MUST -use a `2xx` status code and SHOULD use the `200` status code. - -Note: This indicates that no _GraphQL request error_ was raised, though one or -more _GraphQL field error_ may have been raised this is still a successful -execution - see "partial response" in the GraphQL specification. - -The server SHOULD NOT use a `4xx` or `5xx` status code for a response to a -well-formed _GraphQL-over-HTTP request_. - -Note: For compatibility with legacy servers, this specification allows the use -of `4xx` or `5xx` status codes for a failed well-formed _GraphQL-over-HTTP -request_ where the response uses the `application/json` media type, but it is -strongly discouraged. To use `4xx` and `5xx` status codes in these situations, -please use the `application/graphql-response+json` media type. - -If the URL is not used for other purposes, the server SHOULD use a `4xx` status -code to respond to a request that is not a well-formed _GraphQL-over-HTTP -request_. - -Note: For compatibility with legacy servers, this specification allows the use -of `2xx` or `5xx` status codes when responding to invalid requests using the -`application/json` media type, but it is strongly discouraged. - -Note: URLs that enable GraphQL requests may enable other types of requests - see -the [URL](#url) section. - -### Examples - -The following examples provide guidance on how to deal with specific error cases -when using the `application/json` media type to encode the response body: - -#### JSON parsing failure - -For example a POST request body of `NONSENSE` or `{"query":` (note: invalid -JSON). - -Requests that the server cannot interpret SHOULD result in status code `400` -(Bad Request). - -#### Invalid parameters - -For example a POST request body of `{"qeury": "{__typename}"}` (note: typo) or -`{"query": "query Q ($i:Int!) { q(i: $i) }", "variables": [7]}` (note: invalid -shape for `variables`). - -A request that does not constitute a well-formed _GraphQL-over-HTTP request_ -SHOULD result in status code `400` (Bad Request). - -#### Document parsing failure - -For example a POST request body of `{"query": "{"}`. - -Requests where the _GraphQL document_ cannot be parsed SHOULD result in status -code `200` (Okay). - -#### Document validation failure - -If a request fails to pass _GraphQL validation_, the server SHOULD NOT execute -the request and SHOULD return a status code of `200` (Okay). - -#### Operation cannot be determined - -If [GetOperation()]() raises a -_GraphQL request error_, the server SHOULD NOT execute the request and SHOULD -return a status code of `200` (Okay). - -#### Variable coercion failure - -If -[CoerceVariableValues()]() -raises a _GraphQL request error_, the server SHOULD NOT execute the request and -SHOULD return a status code of `200` (Okay). - -For example the well-formed GraphQL-over-HTTP request: - -```json -{ - "query": "query getItemName($id: ID!) { item(id: $id) { id name } }", - "variables": { "id": null } -} -``` - -would fail variable coercion as the value for `id` would fail to satisfy the -query document's expectation that `id` is non-null. - -#### Field errors encountered during execution - -If the operation is executed and no _GraphQL request error_ is raised then the -server SHOULD respond with a status code of `200` (Okay). This is the case even -if a _GraphQL field error_ is raised during -[GraphQL's ExecuteQuery()]() or -[GraphQL's ExecuteMutation()](). - - diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 26c1a643..231faae6 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -485,32 +485,22 @@ execution regardless of validation errors. ## Status Codes -In case of errors that completely prevent the generation of a well-formed -_GraphQL response_, the server SHOULD respond with the appropriate status code -depending on the concrete error condition. - -Otherwise, the status code to use depends on the media type with which the -GraphQL response will be served. - -For legacy `application/json` responses, see -[Appendix A](#sec-Appendix-application-json-responses). - -### application/graphql-response+json - -This section only applies when the response body uses the -`application/graphql-response+json` media type. - -Clients should process the response as a well-formed _GraphQL response_ -independent of the HTTP status code. +Clients should process a response using the `application/graphql-response+json` +media type as a well-formed _GraphQL response_ independent of the HTTP status +code. Note: With `application/graphql-response+json`, clients know the response is well formed and should determine the detailed status of the response from the response body alone, allowing server authors to adopt more appropriate status -codes without impacting behavior of existing clients. Intermediary servers may -use the status code to determine the status of the _GraphQL response_ without -needing to process the response body; this is useful in request logs, developer -tooling, anomaly and intrusion detection, metrics and observability, API -gateways, and more. +codes without impacting behavior of existing clients. Intermediary servers and +services may use the status code to determine the status of the _GraphQL +response_ without needing to process the response body; this is useful in +request logs, developer tooling, anomaly and intrusion detection, metrics and +observability, API gateways, and more. + +In case of errors that completely prevent the generation of a well-formed +_GraphQL response_, the server SHOULD respond with the appropriate HTTP `4xx` or +`5xx` status code depending on the concrete error condition. If the _GraphQL response_ contains the {data} entry and it is not {null}, then the server MUST reply with a `2xx` status code. @@ -529,7 +519,7 @@ well as encountered errors. Errors that happen during execution of the GraphQL operation typically become part of the result, as long as the server is still able to produce a well-formed _GraphQL response_. For details of why status code `294` is recommended, see [Partial success](#sec-Partial-success). Using `4xx` -and `5xx` status codes in this situation is not appropriate - since no _GraphQL +and `5xx` status codes in this situation is not appropriate: since no _GraphQL request error_ has occurred it is seen as a "partial response" or "partial success". @@ -543,8 +533,9 @@ reply with an appropriate `4xx` or `5xx` status code: - If an unsupported HTTP method is used, status code `405` is RECOMMENDED. - If the `Content-Type` of the request is not supported, status code `415` is RECOMMENDED. - - If none of the media types in the `Accept` header are supported, status code - `406` is RECOMMENDED. + - If none of the media types in the `Accept` header are supported and the + `Accept` header does not include `application/json` then status code `406` + is RECOMMENDED. - If the client did not produce a request within the time that the server was prepared to wait, status code `408` is RECOMMENDED. - If the size of the URI was too large, status code `414` is RECOMMENDED (and @@ -567,10 +558,10 @@ reply with an appropriate `4xx` or `5xx` status code: definitions, status code `422` is RECOMMENDED. - If the client is not permitted to issue the GraphQL request then the server SHOULD reply with `401`, `403` or similar appropriate status code. - - If the server is a short and stout ceramic vessel, status code `418` is - RECOMMENDED. + - If the server cannot process the request due to being a short and stout + ceramic vessel, status code `418` is RECOMMENDED. - When the server is the reason for failure, the appropriate `5xx` status code - should be used; for example, if the server is not able to execute requests at + should be used. For example, if the server is not able to execute requests at this time due to maintenance or load-shedding then status code `503` is RECOMMENDED. @@ -580,9 +571,8 @@ _GraphQL response_ does not include the {data} entry is one in which the #### Examples -The following examples provide guidance on how to deal with specific error cases -when using the `application/graphql-response+json` media type to encode the -response body: +The following examples provide guidance on how to deal with specific error +cases: ##### JSON parsing failure @@ -750,5 +740,3 @@ conflicts with future versions of this specification as ongoing development aims to standardize and ensure the security and interoperability of GraphQL over HTTP whilst accounting for its growing feature set. For this reason, it is recommended to adhere to the officially recognized formats outlined here. - -# [Appendix: application/json](Appendix%20A%20--%20application-json.md) From b4f10b123d2ed9419e505931f4c7bf1e254b0232 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 23 Jun 2026 14:14:23 +0100 Subject: [PATCH 18/22] Decrease header levels --- spec/GraphQLOverHTTP.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 231faae6..c25c61e5 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -569,12 +569,12 @@ Note: The GraphQL specification indicates that the only situation in which the _GraphQL response_ does not include the {data} entry is one in which the {errors} entry is populated. -#### Examples +### Examples The following examples provide guidance on how to deal with specific error cases: -##### JSON parsing failure +#### JSON parsing failure For example a POST request body of `NONSENSE` or `{"query":` (note: invalid JSON). @@ -582,7 +582,7 @@ JSON). Requests that the server cannot interpret should result in status code `400` (Bad Request). -##### Invalid parameters +#### Invalid parameters For example a POST request body of `{"qeury": "{__typename}"}` (note: typo) or `{"query": "query Q ($i:Int!) { q(i: $i) }", "variables": [7]}` (note: invalid @@ -591,32 +591,32 @@ shape for `variables`). A request that does not constitute a well-formed _GraphQL-over-HTTP request_ SHOULD result in status code `422` (Unprocessable Content). -##### Document parsing failure +#### Document parsing failure For example a POST request body of `{"query": "{"}`. Requests where the _GraphQL document_ cannot be parsed should result in status code `400` (Bad Request). -##### Document validation failure +#### Document validation failure If a request fails _GraphQL validation_, the server SHOULD return a status code of `422` (Unprocessable Content) without proceeding to GraphQL execution. -##### Operation cannot be determined +#### Operation cannot be determined If [GetOperation()]() raises a _GraphQL request error_, the server SHOULD NOT execute the request and SHOULD return a status code of `422` (Unprocessable Content). -##### Variable coercion failure +#### Variable coercion failure If [CoerceVariableValues()]() raises a _GraphQL request error_, the server SHOULD NOT execute the request and SHOULD return a status code of `422` (Unprocessable Content). -##### Field errors encountered during execution +#### Field errors encountered during execution If the operation is executed and no _GraphQL request error_ is raised then the server SHOULD respond with a status code of `200` (Okay). This is the case even From 1ea7ee461463675cfd58f5af4781f7f854a947ca Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 23 Jun 2026 14:15:11 +0100 Subject: [PATCH 19/22] Don't use headers --- spec/GraphQLOverHTTP.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index c25c61e5..2f3507ce 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -574,7 +574,7 @@ _GraphQL response_ does not include the {data} entry is one in which the The following examples provide guidance on how to deal with specific error cases: -#### JSON parsing failure +**JSON parsing failure** For example a POST request body of `NONSENSE` or `{"query":` (note: invalid JSON). @@ -582,7 +582,7 @@ JSON). Requests that the server cannot interpret should result in status code `400` (Bad Request). -#### Invalid parameters +**Invalid parameters** For example a POST request body of `{"qeury": "{__typename}"}` (note: typo) or `{"query": "query Q ($i:Int!) { q(i: $i) }", "variables": [7]}` (note: invalid @@ -591,32 +591,32 @@ shape for `variables`). A request that does not constitute a well-formed _GraphQL-over-HTTP request_ SHOULD result in status code `422` (Unprocessable Content). -#### Document parsing failure +**Document parsing failure** For example a POST request body of `{"query": "{"}`. Requests where the _GraphQL document_ cannot be parsed should result in status code `400` (Bad Request). -#### Document validation failure +**Document validation failure** If a request fails _GraphQL validation_, the server SHOULD return a status code of `422` (Unprocessable Content) without proceeding to GraphQL execution. -#### Operation cannot be determined +**Operation cannot be determined** If [GetOperation()]() raises a _GraphQL request error_, the server SHOULD NOT execute the request and SHOULD return a status code of `422` (Unprocessable Content). -#### Variable coercion failure +**Variable coercion failure** If [CoerceVariableValues()]() raises a _GraphQL request error_, the server SHOULD NOT execute the request and SHOULD return a status code of `422` (Unprocessable Content). -#### Field errors encountered during execution +**Field errors encountered during execution** If the operation is executed and no _GraphQL request error_ is raised then the server SHOULD respond with a status code of `200` (Okay). This is the case even From f835f72180d8bbbced75b722d37df5a34dc73e24 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 23 Jun 2026 14:52:44 +0100 Subject: [PATCH 20/22] middlewares -> middleware --- spec/GraphQLOverHTTP.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 2f3507ce..e3cc0095 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -447,9 +447,9 @@ it had `Accept: application/graphql-response+json` but use Note: This recommendation uses this specification's full range of HTTP status codes whilst maximizing compatibility with _legacy client_ for successful and partially successful requests. HTTP responses could originate from non-GraphQL -intermediary servers and middlewares handling failures (HTTP `4xx` and `5xx`), -so clients typically can only rely on a response to be from GraphQL either when -it is successful (HTTP `2xx`) or when it explicitly declares it is a GraphQL +intermediary servers and middleware handling failures (HTTP `4xx` and `5xx`), so +clients typically can only rely on a response to be from GraphQL either when it +is successful (HTTP `2xx`) or when it explicitly declares it is a GraphQL response (`Content-Type: application/graphql-response+json`). If the `Accept` header is present but indicates support for neither any of the From 742d088f9b1679082459fc8d805b466c69632406 Mon Sep 17 00:00:00 2001 From: Benjie Date: Tue, 23 Jun 2026 16:08:43 +0100 Subject: [PATCH 21/22] Fix typo Co-authored-by: Benoit 'BoD' Lubek --- spec/GraphQLOverHTTP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index e3cc0095..f65323fc 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -240,7 +240,7 @@ the `Accept` header. `application/graphql-response+json` media type, and thus does not conform to this specification. -If if is not known that the server supports `application/graphql-response+json`, +If it is not known that the server supports `application/graphql-response+json`, it is RECOMMENDED that the client set the `Accept` header to `application/graphql-response+json, application/json;q=0.9`. From 7f33a000645c4dc0ec87a9f3975f812217b7c489 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 23 Jun 2026 16:26:56 +0100 Subject: [PATCH 22/22] Codex grammar check --- spec/GraphQLOverHTTP.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index f65323fc..bcae71c6 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -434,7 +434,7 @@ specification, when a client does not include at least one supported media type in the `Accept` HTTP header, the server MUST either: 1. Respond with a `406 Not Acceptable` status code and stop processing the - request; OR. + request; OR 1. Disregard the `Accept` header and respond with the server's choice of media type. @@ -452,8 +452,8 @@ clients typically can only rely on a response to be from GraphQL either when it is successful (HTTP `2xx`) or when it explicitly declares it is a GraphQL response (`Content-Type: application/graphql-response+json`). -If the `Accept` header is present but indicates support for neither any of the -server's supported media types nor `application/json`, it is RECOMMENDED to +If the `Accept` header is present but does not indicate support for any of the +server's supported media types or `application/json`, it is RECOMMENDED to respond with `406 Not Acceptable`. Note: It is unlikely that a client can process a response that does not match @@ -490,7 +490,7 @@ media type as a well-formed _GraphQL response_ independent of the HTTP status code. Note: With `application/graphql-response+json`, clients know the response is -well formed and should determine the detailed status of the response from the +well-formed and should determine the detailed status of the response from the response body alone, allowing server authors to adopt more appropriate status codes without impacting behavior of existing clients. Intermediary servers and services may use the status code to determine the status of the _GraphQL @@ -506,13 +506,13 @@ If the _GraphQL response_ contains the {data} entry and it is not {null}, then the server MUST reply with a `2xx` status code. If the _GraphQL response_ contains the {data} entry and does not contain the -{errors} entry, then the server SHOULD reply with `200` status code. +{errors} entry, then the server SHOULD reply with a `200` status code. Note: There are no circumstances where the GraphQL specification allows for a response having {data} as {null} without {errors} being present. If the _GraphQL response_ contains both the {data} entry (even if it is {null}) -and the {errors} entry, then the server SHOULD reply with `294` status code. +and the {errors} entry, then the server SHOULD reply with a `294` status code. Note: The result of executing a GraphQL operation may contain partial data as well as encountered errors. Errors that happen during execution of the GraphQL @@ -534,7 +534,7 @@ reply with an appropriate `4xx` or `5xx` status code: - If the `Content-Type` of the request is not supported, status code `415` is RECOMMENDED. - If none of the media types in the `Accept` header are supported and the - `Accept` header does not include `application/json` then status code `406` + `Accept` header does not include `application/json`, then status code `406` is RECOMMENDED. - If the client did not produce a request within the time that the server was prepared to wait, status code `408` is RECOMMENDED. @@ -556,13 +556,13 @@ reply with an appropriate `4xx` or `5xx` status code: `422` is RECOMMENDED. - If the variable values cannot be coerced to match the operation's variable definitions, status code `422` is RECOMMENDED. - - If the client is not permitted to issue the GraphQL request then the server + - If the client is not permitted to issue the GraphQL request, then the server SHOULD reply with `401`, `403` or similar appropriate status code. - If the server cannot process the request due to being a short and stout ceramic vessel, status code `418` is RECOMMENDED. - When the server is the reason for failure, the appropriate `5xx` status code should be used. For example, if the server is not able to execute requests at - this time due to maintenance or load-shedding then status code `503` is + this time due to maintenance or load-shedding, then status code `503` is RECOMMENDED. Note: The GraphQL specification indicates that the only situation in which the @@ -576,7 +576,7 @@ cases: **JSON parsing failure** -For example a POST request body of `NONSENSE` or `{"query":` (note: invalid +For example, a POST request body of `NONSENSE` or `{"query":` (note: invalid JSON). Requests that the server cannot interpret should result in status code `400` @@ -584,7 +584,7 @@ Requests that the server cannot interpret should result in status code `400` **Invalid parameters** -For example a POST request body of `{"qeury": "{__typename}"}` (note: typo) or +For example, a POST request body of `{"qeury": "{__typename}"}` (note: typo) or `{"query": "query Q ($i:Int!) { q(i: $i) }", "variables": [7]}` (note: invalid shape for `variables`). @@ -593,7 +593,7 @@ SHOULD result in status code `422` (Unprocessable Content). **Document parsing failure** -For example a POST request body of `{"query": "{"}`. +For example, a POST request body of `{"query": "{"}`. Requests where the _GraphQL document_ cannot be parsed should result in status code `400` (Bad Request). @@ -618,7 +618,7 @@ SHOULD return a status code of `422` (Unprocessable Content). **Field errors encountered during execution** -If the operation is executed and no _GraphQL request error_ is raised then the +If the operation is executed and no _GraphQL request error_ is raised, then the server SHOULD respond with a status code of `200` (Okay). This is the case even if a _GraphQL field error_ is raised during [GraphQL's ExecuteQuery()]() or