Previous to this specification, the article Serving over HTTP (WayBack Machine entry, 1st June 2022) 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 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.
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.
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 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 section.
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:
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).
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).
For example a POST request body of {"query": "{"}.
Requests where the GraphQL document cannot be parsed SHOULD result in status
code 200 (Okay).
If a request fails to pass GraphQL validation, the server SHOULD NOT execute
the request and SHOULD return a status code of 200 (Okay).
If GetOperation() raises a
GraphQL request error, the server SHOULD NOT execute the request and SHOULD
return a status code of 200 (Okay).
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:
{
"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.
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().