From 957aa9429d8749fc7494434cfeeddecfd7c24dd9 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 19:23:06 +0200 Subject: [PATCH 1/8] 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 c8b14751..d2148438 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 5a102c49464da461a421cfdd2fd60562d88e9b4e Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 19:29:27 +0200 Subject: [PATCH 2/8] 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 0ded3c48ef5742d51a4f4f3a019b536fbac7a4c4 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 19:30:52 +0200 Subject: [PATCH 3/8] 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 4603e0037bdc1921d3d657acaf77f0c1fbe44269 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Fri, 3 Apr 2026 11:57:20 +0200 Subject: [PATCH 4/8] 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 d2148438..efa1ab9e 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 712e6cc2a67af4d3a3690ae70797cd27f86cb0ae Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Fri, 3 Apr 2026 22:59:19 +0200 Subject: [PATCH 5/8] 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 efa1ab9e..0eedad89 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -242,21 +242,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 855e7baa63bf03fa7b368223721a0d0e3cc530bb Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Fri, 3 Apr 2026 23:06:30 +0200 Subject: [PATCH 6/8] 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 0eedad89..56ef4eea 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 499886636d6cf54cbc4e41e3b4dc493b2ba5ad8c Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Fri, 3 Apr 2026 23:08:05 +0200 Subject: [PATCH 7/8] 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 56ef4eea..143beff8 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 aa6db2d85c44304e1d99ba8f8c856645c25eff59 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 23 Apr 2026 14:41:10 +0200 Subject: [PATCH 8/8] 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 143beff8..bf99de5e 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -242,6 +242,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