From 17600a0b510d11d051d019b8b48050a90e6a1448 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 00:28:30 +0200 Subject: [PATCH 01/22] Remove the security note, we have a non-normative note now --- spec/GraphQLOverHTTP.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 8f3c9894..095e8e20 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -167,8 +167,6 @@ The GraphQL specification allows for many Servers and clients MUST support JSON and MAY support other, additional serialization formats. -Note: Allowing other media types, particularly on requests, can be insecure. - For consistency and ease of notation, examples of the response are given in JSON throughout this specification. From 9a1ecb5f4a19dbf96d9da39060d936a45070ed9b Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 00:46:48 +0200 Subject: [PATCH 02/22] remove the table from the media types --- spec/GraphQLOverHTTP.md | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 095e8e20..e3826546 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -162,31 +162,17 @@ http://example.com/product/graphql # Serialization Format -The GraphQL specification allows for many -[serialization formats to be implemented](https://spec.graphql.org/draft/#sec-Serialization-Format). -Servers and clients MUST support JSON and MAY support other, additional -serialization formats. - -For consistency and ease of notation, examples of the response are given in JSON -throughout this specification. +Servers and clients MUST support JSON as a serialization format. ## 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_: -| Name | Description | -| ----------------------------------- | --------------------------------------- | -| `application/graphql-response+json` | The preferred type for server responses | +The following are the officially recognized GraphQL media types: -Note: Servers MAY additionally support `application/json` as a response media -type. +| 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). From 1b5b3588915398ce01767252fe0739e0b56779ba Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 00:49:15 +0200 Subject: [PATCH 03/22] Add compatibility non-normative note --- spec/GraphQLOverHTTP.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index e3826546..c615109f 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 @@ -584,6 +576,17 @@ 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. +## Compatibility + +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. Leading implementations on +both client and server have mostly upheld those best practices and thus +established a de-facto standard commonly used throughout the ecosystem. + + + ## Security This specification focuses solely on the intersection of GraphQL and HTTP. From 4d27afb72532c184271c584eb8454c2d265aa3b7 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 00:53:38 +0200 Subject: [PATCH 04/22] Focus on JSON --- spec/GraphQLOverHTTP.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index c615109f..aeb36565 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -158,7 +158,6 @@ Servers and clients MUST support JSON as a serialization format. ## Media Types - The following are the officially recognized GraphQL media types: | Name | Description | @@ -207,10 +206,6 @@ string describing one or more operations, each of which may be a query or mutation. A better name would have been `document`, but the term `query` is well established. -Note: Depending on the serialization format used, values of the aforementioned -parameters can be encoded differently but their names and semantics must stay -the same. - Note: An HTTP request that encodes parameters of the same names but of the wrong type, or that omits required parameters, is not a well-formed _GraphQL-over-HTTP request_. From 5db9534e9df9f154eac43cecc3496a6ba9681c2d Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 00:54:25 +0200 Subject: [PATCH 05/22] Do not repeat ourselves --- spec/GraphQLOverHTTP.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index aeb36565..2ecb83f5 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -206,10 +206,6 @@ string describing one or more operations, each of which may be a query or mutation. A better name would have been `document`, but the term `query` is well established. -Note: An HTTP request that encodes parameters of the same names but of the wrong -type, or that omits required parameters, is not a well-formed _GraphQL-over-HTTP -request_. - Note: Specifying `null` for optional request parameters is equivalent to not specifying them at all. From f5294082d313e3e02d4bbc6c7e91e441162ba2cc Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 00:56:45 +0200 Subject: [PATCH 06/22] Be explicit that null or absent is equivalent to an empty map --- spec/GraphQLOverHTTP.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 2ecb83f5..272faa83 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -206,8 +206,8 @@ string describing one or more operations, each of which may be a query or mutation. A better name would have been `document`, but the term `query` is well established. -Note: Specifying `null` for optional request parameters is equivalent to not -specifying them at all. +Note: For robustness, specifying `null` for optional request parameters is equivalent to not +specifying them at all. For the map parameters, this is equivalent to specifying them as an empty map. Note: So long as it is a string, {query} does not have to parse or validate to be part of a well-formed _GraphQL-over-HTTP request_. From 1666f2a6be52852201dbb64cbd0746cf7e528d2e Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 00:57:47 +0200 Subject: [PATCH 07/22] Move Accept compatibility to compatibility section --- spec/GraphQLOverHTTP.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 272faa83..de8b4fb3 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -221,10 +221,6 @@ A client MUST indicate the media types that it supports in responses using the The client MUST include the media type `application/graphql-response+json` in the `Accept` header. -The client MAY additionally include the media type `application/json` in the -`Accept` header. 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 @@ -577,6 +573,10 @@ both client and server have mostly upheld those best practices and thus established a de-facto standard commonly used throughout the ecosystem. +The client MAY additionally include the media type `application/json` in the +`Accept` header. When accepting both media types, the client SHOULD indicate it +prefers `application/graphql-response+json` over `application/json`. + ## Security From 8e8705768a0947f411d6c33a5b49591980fb3855 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 00:59:39 +0200 Subject: [PATCH 08/22] no exception for the empty string --- spec/GraphQLOverHTTP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index de8b4fb3..ba5179aa 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -237,7 +237,7 @@ The {operationName} parameter, if present, must be a string. Each of the {variables} and {extensions} parameters, if used, MUST be encoded as a JSON string. -The {operationName} parameter, if supplied and not the empty string, represents +The {operationName} parameter, if supplied, represents the name of the operation to be executed within the {query} as a string. Note: In the final URL all of these parameters will appear in the query From 4ad42d3712d3a7e1179adcb38cc8ca47dbebb1d9 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 01:04:27 +0200 Subject: [PATCH 09/22] move POST null parameters outside of a note, this is normative --- spec/GraphQLOverHTTP.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index ba5179aa..e30fc4b3 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -195,6 +195,9 @@ parameters in one of the manners described in this specification: extend the protocol however they see fit, as specified in [the Response section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Response-Format.Response). +For robustness, specifying `null` for optional request parameters is equivalent to not +specifying them at all. + Note: When comparing _GraphQL-over-HTTP request_ against the term ["request"](https://spec.graphql.org/draft/#request) in the GraphQL specification you should note the _GraphQL schema_ and "initial value" are not @@ -206,9 +209,6 @@ string describing one or more operations, each of which may be a query or mutation. A better name would have been `document`, but the term `query` is well established. -Note: For robustness, specifying `null` for optional request parameters is equivalent to not -specifying them at all. For the map parameters, this is equivalent to specifying them as an empty map. - Note: So long as it is a string, {query} does not have to parse or validate to be part of a well-formed _GraphQL-over-HTTP request_. @@ -248,8 +248,7 @@ Setting the value of the {operationName} parameter to the empty string is equivalent to omitting the {operationName} parameter. Note: By the above, `operationName=null` represents an operation with the name -`"null"` (such as `query null { __typename }`). If a literal `null` is desired, -either omit {operationName} or set it to the empty string. +`"null"` (such as `query null { __typename }`). ### Example From 927988cae0d31b4a4c5dd2e88d476f91dc819569 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 01:08:57 +0200 Subject: [PATCH 10/22] consistency --- spec/GraphQLOverHTTP.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index e30fc4b3..d951e0a5 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -232,12 +232,12 @@ The {query} parameter MUST be the string representation of the source text of the document as specified in [the Language section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Language). -The {operationName} parameter, if present, must be a string. +The {operationName} parameter, if present, MUST be a string. -Each of the {variables} and {extensions} parameters, if used, MUST be encoded as -a JSON string. +Each of the {variables} and {extensions} parameters, if present, MUST be encoded as +a JSON object string. -The {operationName} parameter, if supplied, represents +The {operationName} parameter, if present, represents the name of the operation to be executed within the {query} as a string. Note: In the final URL all of these parameters will appear in the query @@ -375,7 +375,7 @@ And the body: When a server receives a well-formed _GraphQL-over-HTTP request_, it must return a well‐formed _GraphQL response_. The server's response describes the result of -validating and executing the requested operation if successful, and describes +validating and executing the requested operation if successful and describes any errors encountered during the request. A server must comply with From 1c5c1bdca66d9bcb828519a6491c5ec2a26b1f3a Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 01:10:58 +0200 Subject: [PATCH 11/22] Move the "ignore unknown keys" above because it applies to both GET and POST --- spec/GraphQLOverHTTP.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index d951e0a5..24064e27 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -198,6 +198,9 @@ parameters in one of the manners described in this specification: For robustness, specifying `null` for optional request parameters is equivalent to not specifying them at all. +Servers receiving a request with additional properties MUST ignore properties +they do not understand. + Note: When comparing _GraphQL-over-HTTP request_ against the term ["request"](https://spec.graphql.org/draft/#request) in the GraphQL specification you should note the _GraphQL schema_ and "initial value" are not @@ -329,9 +332,6 @@ to add additional information to a request they MUST do so via other means; the RECOMMENDED approach is to add an implementer-scoped entry to the {extensions} object. -Servers receiving a request with additional properties MUST ignore properties -they do not understand. - ### Example If we wanted to execute the following GraphQL query: From 1294d6b8798db379c65def00f7e50b14cdb71cfe Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 01:17:12 +0200 Subject: [PATCH 12/22] Move the 'null' references to the POST section. It doesn't make much sense for GET --- spec/GraphQLOverHTTP.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 24064e27..a54df8c3 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -195,9 +195,6 @@ parameters in one of the manners described in this specification: extend the protocol however they see fit, as specified in [the Response section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Response-Format.Response). -For robustness, specifying `null` for optional request parameters is equivalent to not -specifying them at all. - Servers receiving a request with additional properties MUST ignore properties they do not understand. @@ -240,16 +237,15 @@ The {operationName} parameter, if present, MUST be a string. Each of the {variables} and {extensions} parameters, if present, MUST be encoded as a JSON object string. -The {operationName} parameter, if present, represents +For robustness, specifying the empty string for optional request parameters is equivalent to not specifying them at all. + +The {operationName} parameter, if present and not the empty string, represents the name of the operation to be executed within the {query} as a string. Note: In the final URL all of these parameters will appear in the query component of the request URL as URL-encoded values due to the WHATWG URLSearchParams encoding specified above. -Setting the value of the {operationName} parameter to the empty string is -equivalent to omitting the {operationName} parameter. - Note: By the above, `operationName=null` represents an operation with the name `"null"` (such as `query null { __typename }`). @@ -286,6 +282,9 @@ operation. A GraphQL POST 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. +For robustness, specifying `null` for optional request parameters is equivalent to not +specifying them at all. + A client MUST indicate the media type of a request body using the `Content-Type` header as specified in [RFC7231](https://datatracker.ietf.org/doc/html/rfc7231). From 55e886ed7165be10b7414fdd7747ad47d52aef20 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 01:20:44 +0200 Subject: [PATCH 13/22] move the GET requests MUST not be mutations above examples --- spec/GraphQLOverHTTP.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index a54df8c3..c62231e1 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -232,7 +232,7 @@ The {query} parameter MUST be the string representation of the source text of the document as specified in [the Language section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Language). -The {operationName} parameter, if present, MUST be a string. +The {operationName} parameter, if present and not the empty string, MUST be a string. Each of the {variables} and {extensions} parameters, if present, MUST be encoded as a JSON object string. @@ -242,6 +242,12 @@ For robustness, specifying the empty string for optional request parameters is e The {operationName} parameter, if present and not the empty string, represents the name of the operation to be executed within the {query} as a string. +GET requests MUST NOT be used for executing mutation operations. If the values +of {query} and {operationName} indicate that a mutation operation is to be +executed, the server MUST respond with error status code `405` (Method Not +Allowed) and halt execution. This restriction is necessary to conform with the +long-established semantics of safe methods within HTTP. + Note: In the final URL all of these parameters will appear in the query component of the request URL as URL-encoded values due to the WHATWG URLSearchParams encoding specified above. @@ -269,11 +275,6 @@ This request could be sent via an HTTP GET as follows: http://example.com/graphql?query=query(%24id%3A%20ID!)%7Buser(id%3A%24id)%7Bname%7D%7D&variables=%7B%22id%22%3A%22QVBJcy5ndXJ1%22%7D ``` -GET requests MUST NOT be used for executing mutation operations. If the values -of {query} and {operationName} indicate that a mutation operation is to be -executed, the server MUST respond with error status code `405` (Method Not -Allowed) and halt execution. This restriction is necessary to conform with the -long-established semantics of safe methods within HTTP. ## POST From 6730a8b2d099df470aae6057f8d986c5f26c15b8 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 01:33:39 +0200 Subject: [PATCH 14/22] Add another example for GET. Keep GET and POST sections symmetrical --- spec/GraphQLOverHTTP.md | 58 ++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index c62231e1..a33ef8bc 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -198,6 +198,10 @@ parameters in one of the manners described in this specification: Servers receiving a request with additional properties MUST ignore properties they do not understand. +If implementers need to add additional information to a request, they MUST do so via other means; the +RECOMMENDED approach is to add an implementer-scoped entry to the {extensions} +object. + Note: When comparing _GraphQL-over-HTTP request_ against the term ["request"](https://spec.graphql.org/draft/#request) in the GraphQL specification you should note the _GraphQL schema_ and "initial value" are not @@ -255,7 +259,7 @@ URLSearchParams encoding specified above. Note: By the above, `operationName=null` represents an operation with the name `"null"` (such as `query null { __typename }`). -### Example +### Examples If we wanted to execute the following GraphQL query: @@ -275,16 +279,27 @@ This request could be sent via an HTTP GET as follows: http://example.com/graphql?query=query(%24id%3A%20ID!)%7Buser(id%3A%24id)%7Bname%7D%7D&variables=%7B%22id%22%3A%22QVBJcy5ndXJ1%22%7D ``` +An empty {operationName} is allowed. This is a valid request: + +```url example +http://example.com/graphql?query=%7B%20foo%20%7D&operationName= +``` + ## 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 -_GraphQL-over-HTTP request_ parameters encoded in one of the officially -recognized GraphQL media types, or another media type supported by the server. +A GraphQL POST request MUST have a body which contains values of the +_GraphQL-over-HTTP request_ parameters encoded using the `application/json` media type. + +The {query} parameter MUST be the string representation of the source text of +the document as specified in +[the Language section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Language). + +The {operationName} parameter, if present and not null, MUST be a string. + +Each of the {variables} and {extensions} parameters, if present and not null, MUST be a JSON object. -For robustness, specifying `null` for optional request parameters is equivalent to not -specifying them at all. +For robustness, specifying null for optional request parameters is equivalent to not specifying them at all. A client MUST indicate the media type of a request body using the `Content-Type` header as specified in [RFC7231](https://datatracker.ietf.org/doc/html/rfc7231). @@ -303,35 +318,6 @@ header with every POST request. A server has the option to assume any media type they wish when none is supplied, with the understanding that parsing the request may fail. -A server MAY support POST requests encoded with and/or accepting other media -types or encodings. - -If a client does not know the media types the server supports then it SHOULD -encode the request body in JSON (i.e. with `Content-Type: application/json`). - -Note: Request encoding with media type `application/json` is supported by every -compliant _server_. - -### JSON Encoding - -When encoded in JSON, a _GraphQL-over-HTTP request_ is encoded as a JSON object -(map), with the properties specified by the GraphQL-over-HTTP request: - -- {query} - the string representation of the Source Text of the Document as - specified in - [the Language section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Language). -- {operationName} - an optional string -- {variables} - an optional object (map), the keys of which are the variable - names and the values of which are the variable values -- {extensions} - an optional object (map) reserved for implementers to extend - the protocol however they see fit, as specified in - [the Response section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Response-Format.Response). - -All other property names are reserved for future expansion. If implementers need -to add additional information to a request they MUST do so via other means; the -RECOMMENDED approach is to add an implementer-scoped entry to the {extensions} -object. - ### Example If we wanted to execute the following GraphQL query: From ef19088cd1c377ab8362b50aabf1e1ec0fbc2ac8 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 01:51:57 +0200 Subject: [PATCH 15/22] 200 is not necessarily good? --- spec/GraphQLOverHTTP.md | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index a33ef8bc..51fb4cd6 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -198,7 +198,7 @@ parameters in one of the manners described in this specification: Servers receiving a request with additional properties MUST ignore properties they do not understand. -If implementers need to add additional information to a request, they MUST do so via other means; the +If implementers need to add additional information to a request they MUST do so via other means; the RECOMMENDED approach is to add an implementer-scoped entry to the {extensions} object. @@ -372,14 +372,19 @@ A server must comply with The body of the server's response MUST follow the requirements for a _GraphQL response_, encoded directly in the chosen media type. -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`). - 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. +A _server_ MUST support responses using the `application/graphql-response+json` +media type. + +A server MAY additionally support other response media types. + +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`). + In alignment with the [HTTP 1.1 Accept](https://tools.ietf.org/html/rfc7231#section-5.3.2) specification, when a client does not include at least one supported media type @@ -395,15 +400,6 @@ 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 the `application/graphql-response+json` -media type. - -A server MAY additionally support the `application/json` response media type. - -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. - ## Validation Validation of a well-formed _GraphQL-over-HTTP request_ SHOULD apply all the @@ -426,7 +422,7 @@ should not be executed; however in certain circumstances, for example persisted operations that were previously known to be valid, the server may attempt execution regardless of validation errors. -## Status Codes +## Status Code In case of errors that completely prevent the generation of a well-formed _GraphQL response_, the server MUST respond with the appropriate status code @@ -436,8 +432,7 @@ status code. Note: Typically the appropriate status code will be `400` (Bad Request). If the _GraphQL response_ contains the {data} entry and it is not {null}, then -the server MUST reply with a `2xx` status code and SHOULD reply with `200` -status code. +the server MUST reply with a `2xx` 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 @@ -452,12 +447,11 @@ are expected to be supported over time, valid codes must be present in this document. If the _GraphQL response_ contains the {data} entry and it is {null}, then the -server SHOULD reply with a `2xx` status code and it is RECOMMENDED it replies -with `200` status code. +server SHOULD reply with a `2xx` status code. Note: Using `4xx` and `5xx` status codes in this situation is not recommended - since no _GraphQL request error_ has occurred it is seen as a "partial -response". +response". This is typically the case if an error is propagated to the root field. If the _GraphQL response_ does not contain the {data} entry then the server MUST reply with a `4xx` or `5xx` status code as appropriate. @@ -557,6 +551,9 @@ on the graphql.org website served as guidance. Leading implementations on both client and server have mostly upheld those best practices and thus established a de-facto standard commonly used throughout the ecosystem. +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. The client MAY additionally include the media type `application/json` in the `Accept` header. When accepting both media types, the client SHOULD indicate it From d7100a897a35b39b676d4595a5f5d360a7af937a Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 01:59:54 +0200 Subject: [PATCH 16/22] move down --- spec/GraphQLOverHTTP.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 51fb4cd6..c1b22011 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -466,10 +466,6 @@ pass validation, then the server SHOULD reply with `400` status code. If the client is not permitted to issue the GraphQL request then the server SHOULD reply with `403`, `401` or similar appropriate status code. -Note: 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 @@ -559,6 +555,10 @@ The client MAY additionally include the media type `application/json` in the `Accept` header. When accepting both media types, the client SHOULD indicate it prefers `application/graphql-response+json` over `application/json`. +Note: 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. ## Security From 693d036dd2fb95998a8d11cf328de468ec455dc6 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 02:16:29 +0200 Subject: [PATCH 17/22] Add application/json media type --- spec/GraphQLOverHTTP.md | 60 +++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index c1b22011..16b5671d 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -538,27 +538,65 @@ 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. -## Compatibility +## `application/json` response media type 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. Leading implementations on -both client and server have mostly upheld those best practices and thus -established a de-facto standard commonly used throughout the ecosystem. +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. + +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. -The client MAY additionally include the media type `application/json` in the -`Accept` header. When accepting both media types, the client SHOULD indicate it -prefers `application/graphql-response+json` over `application/json`. +### 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 code + +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_. + +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: 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. +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_. ## Security From 7d29901fb451f92416f032572ffec00fe80fc220 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 02:16:57 +0200 Subject: [PATCH 18/22] format --- spec/GraphQLOverHTTP.md | 62 +++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 16b5671d..ed32754c 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -161,7 +161,7 @@ Servers and clients MUST support JSON as a serialization format. The following are the officially recognized GraphQL media types: | Name | Description | -|-------------------------------------|---------------------------------------| +| ----------------------------------- | ------------------------------------- | | `application/json` | Media type for GraphQL JSON requests | | `application/graphql-response+json` | Media type for GraphQL JSON responses | @@ -198,9 +198,9 @@ parameters in one of the manners described in this specification: Servers receiving a request with additional properties MUST ignore properties they do not understand. -If implementers need to add additional information to a request they MUST do so via other means; the -RECOMMENDED approach is to add an implementer-scoped entry to the {extensions} -object. +If implementers need to add additional information to a request they MUST do so +via other means; the RECOMMENDED approach is to add an implementer-scoped entry +to the {extensions} object. Note: When comparing _GraphQL-over-HTTP request_ against the term ["request"](https://spec.graphql.org/draft/#request) in the GraphQL @@ -236,12 +236,14 @@ The {query} parameter MUST be the string representation of the source text of the document as specified in [the Language section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Language). -The {operationName} parameter, if present and not the empty string, MUST be a string. +The {operationName} parameter, if present and not the empty string, MUST be a +string. -Each of the {variables} and {extensions} parameters, if present, MUST be encoded as -a JSON object string. +Each of the {variables} and {extensions} parameters, if present, MUST be encoded +as a JSON object string. -For robustness, specifying the empty string for optional request parameters is equivalent to not specifying them at all. +For robustness, specifying the empty string for optional request parameters is +equivalent to not specifying them at all. The {operationName} parameter, if present and not the empty string, represents the name of the operation to be executed within the {query} as a string. @@ -257,7 +259,7 @@ component of the request URL as URL-encoded values due to the WHATWG URLSearchParams encoding specified above. Note: By the above, `operationName=null` represents an operation with the name -`"null"` (such as `query null { __typename }`). +`"null"` (such as `query null { __typename }`). ### Examples @@ -285,11 +287,11 @@ An empty {operationName} is allowed. This is a valid request: http://example.com/graphql?query=%7B%20foo%20%7D&operationName= ``` - ## POST A GraphQL POST request MUST have a body which contains values of the -_GraphQL-over-HTTP request_ parameters encoded using the `application/json` media type. +_GraphQL-over-HTTP request_ parameters encoded using the `application/json` +media type. The {query} parameter MUST be the string representation of the source text of the document as specified in @@ -297,9 +299,11 @@ the document as specified in The {operationName} parameter, if present and not null, MUST be a string. -Each of the {variables} and {extensions} parameters, if present and not null, MUST be a JSON object. +Each of the {variables} and {extensions} parameters, if present and not null, +MUST be a JSON object. -For robustness, specifying null for optional request parameters is equivalent to not specifying them at all. +For robustness, specifying null for optional request parameters is equivalent to +not specifying them at all. A client MUST indicate the media type of a request body using the `Content-Type` header as specified in [RFC7231](https://datatracker.ietf.org/doc/html/rfc7231). @@ -361,8 +365,8 @@ And the body: When a server receives a well-formed _GraphQL-over-HTTP request_, it must return a well‐formed _GraphQL response_. The server's response describes the result of -validating and executing the requested operation if successful and describes -any errors encountered during the request. +validating and executing the requested operation if successful and describes any +errors encountered during the request. A server must comply with [RFC7231](https://datatracker.ietf.org/doc/html/rfc7231). @@ -451,7 +455,8 @@ server SHOULD reply with a `2xx` status code. Note: Using `4xx` and `5xx` status codes in this situation is not recommended - since no _GraphQL request error_ has occurred it is seen as a "partial -response". This is typically the case if an error is propagated to the root field. +response". This is typically the case if an error is propagated to the root +field. If the _GraphQL response_ does not contain the {data} entry then the server MUST reply with a `4xx` or `5xx` status code as appropriate. @@ -466,7 +471,6 @@ pass validation, then the server SHOULD reply with `400` status code. If the client is not permitted to issue the GraphQL request then the server SHOULD reply with `403`, `401` or similar appropriate status code. - ### Examples The following examples provide guidance on how to deal with specific error @@ -543,7 +547,7 @@ phrases specified in RFC2119 are used. 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. +on the graphql.org website served as guidance. This article used `application/json` as media type for the response. @@ -555,12 +559,15 @@ 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`. +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. +This caused multiple observability issues because it was challenging to +distinguish a well-formed _GraphQL response_ from an intermediary response. -For compatibility reasons, clients and servers may support `application/json` as described in this section. +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 @@ -568,8 +575,9 @@ 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 +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` @@ -577,9 +585,9 @@ should only be used if `application/graphql-response+json` is not supported. ### Status code -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 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_. From 330943279dbd9d6f06d7fd4d4fc0bbbc4b2c761c Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 02:19:48 +0200 Subject: [PATCH 19/22] formating --- spec/GraphQLOverHTTP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index ed32754c..62a848d9 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -542,7 +542,7 @@ 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. -## `application/json` response media type +## application/json response media type Previous to this specification, the article [Serving over HTTP](https://graphql.org/learn/serving-over-http) From caeae1361287b5bb225731b556324ca393f99f88 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 10:37:13 +0200 Subject: [PATCH 20/22] Do not use uppercase in non-normative notes --- spec/GraphQLOverHTTP.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 62a848d9..1619f7ad 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -575,8 +575,8 @@ 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 +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`. @@ -585,24 +585,24 @@ should only be used if `application/graphql-response+json` is not supported. ### Status code -When using the `application/json` media type, the server SHOULD use the `200` +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 +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_. -If the _GraphQL response_ contains a non-null {data} entry then the server MUST +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 +The server should not use a `4xx` or `5xx` status code for a response to a well-formed _GraphQL-over-HTTP request_. -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_. From 956bcfb9d44e8f73072668e7cc5d74357df5576e Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 10:53:07 +0200 Subject: [PATCH 21/22] Move all status code requirements to the status code section --- spec/GraphQLOverHTTP.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index 1619f7ad..b65a0c56 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -248,11 +248,9 @@ equivalent to not specifying them at all. The {operationName} parameter, if present and not the empty string, represents the name of the operation to be executed within the {query} as a string. -GET requests MUST NOT be used for executing mutation operations. If the values -of {query} and {operationName} indicate that a mutation operation is to be -executed, the server MUST respond with error status code `405` (Method Not -Allowed) and halt execution. This restriction is necessary to conform with the -long-established semantics of safe methods within HTTP. +GET requests MUST NOT be used for executing mutation operations. This +restriction is necessary to conform with the long-established semantics of safe +methods within HTTP. Note: In the final URL all of these parameters will appear in the query component of the request URL as URL-encoded values due to the WHATWG @@ -317,6 +315,10 @@ indicating an encoding, the server MUST assume the encoding is `utf-8`. If the client does not supply a `Content-Type` header with a POST request, the server SHOULD reject the request using the appropriate `4xx` status code. +If the values of {query} and {operationName} indicate that a mutation operation +is to be executed with a GET request, the server MUST respond with error status +code `405` (Method Not Allowed) and halt execution. + Note: Rejecting such requests encourages clients to supply a `Content-Type` header with every POST request. A server has the option to assume any media type they wish when none is supplied, with the understanding that parsing the request From 691155fec958917589614074a8a3ce73b161c904 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 2 Apr 2026 11:07:41 +0200 Subject: [PATCH 22/22] Add an extra sentence to help with the reading flow --- spec/GraphQLOverHTTP.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index b65a0c56..3fa9480a 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -568,6 +568,10 @@ 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.