Skip to content

Commit d67803b

Browse files
committed
Restore important guidance and recommend support for Accept:application/json
1 parent 8f2eb8a commit d67803b

2 files changed

Lines changed: 108 additions & 60 deletions

File tree

spec/Appendix A -- application-json.md

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
# A. Appendix: `application/json` responses
22

3+
This section only applies when the response body uses or may use the legacy
4+
`application/json` media type for compatibility reasons.
5+
36
Previous to this specification, the article
47
[Serving over HTTP](https://graphql.org/learn/serving-over-http)
58
([WayBack Machine entry, 1st June 2022](https://web.archive.org/web/20220601155421/https://graphql.org/learn/serving-over-http))
6-
on the graphql.org website served as guidance.
7-
8-
This article used `application/json` as media type for the response.
9+
on the graphql.org website served as guidance. This article used
10+
`application/json` as media type for the response.
911

1012
In some cases, the response received by a client may not originate from a
1113
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
1517
`application/json` media type to encode the reason for the error. Such a
1618
response is unlikely to be a valid GraphQL response.
1719

18-
For this reason, a client application receiving an `application/json` response,
19-
could rely on the response being a well-formed _GraphQL response_ only if the
20-
status code is `200`.
21-
22-
This caused multiple observability issues because it was challenging to
23-
distinguish a well-formed _GraphQL response_ from an intermediary response.
24-
25-
`application/graphql-response+json` allows to distinguish a well-formed _GraphQL
26-
response_ from another intermediary response and is the required media type
27-
moving forward.
28-
29-
For compatibility reasons, clients and servers may support `application/json` as
30-
described in this section.
31-
32-
Note: Servers may wish to only support the `application/graphql-response+json`
33-
media type so that related HTTP tooling may utilize the HTTP status codes of
34-
responses without having to be GraphQL-aware.
35-
36-
### Accept
37-
38-
To maximize compatibility, a client may include the media type
39-
`application/json` in the `Accept` header. When doing this, it is recommended
40-
that the client set the `Accept` header to
20+
For this reason, a client receiving an `application/json` response can only rely
21+
on the response being a well-formed _GraphQL response_ if the status code is
22+
`200`. However, responding to all GraphQL requests with HTTP 200 means that
23+
intermediary observability software cannot determine the status of the request
24+
without processing the response body.
25+
26+
Responding with the `application/graphql-response+json` media type enables the
27+
client to distinguish a well-formed _GraphQL response_ from an intermediary
28+
response, and is required by both clients and servers under this specification.
29+
This appendix exists to increase interoperability with legacy clients/servers
30+
that have not yet adopted this specification.
31+
32+
Note: Servers may wish to respond to `Accept: application/json` requests with
33+
the `application/graphql-response+json` media type so that related HTTP tooling
34+
may utilize the HTTP status codes of responses without having to be
35+
GraphQL-aware. Doing so may impact error-handling behavior of legacy clients,
36+
and may prevent legacy clients from processing responses if they require the
37+
response `Content-Type` to be `application/json`.
38+
39+
## Accept
40+
41+
To enable compatibility with legacy servers, the client SHOULD include the media
42+
type `application/json` in the `Accept` header and it is RECOMMENDED that such a
43+
client set the `Accept` header to
4144
`application/graphql-response+json, application/json;q=0.9`.
4245

4346
Note: The `q=0.9` parameter tells content negotiation that `application/json`
4447
should only be used if `application/graphql-response+json` is not supported.
4548

46-
### Status codes
49+
## Status codes
4750

48-
When using the `application/json` media type, the server should use the `200`
49-
status code for every response to a well-formed _GraphQL-over-HTTP request_,
50-
independent of any _GraphQL request error_ or _GraphQL field error_ raised.
51+
When responding with the legacy `application/json` media type, the server SHOULD
52+
use the `200` status code for every response to a well-formed _GraphQL-over-HTTP
53+
request_ independent of any _GraphQL request error_ or _GraphQL field error_
54+
raised.
5155

52-
If the response uses a non-`200` status code then the client must not rely on
56+
If the response uses a non-`2xx` status code then the client MUST NOT rely on
5357
the body to be a well-formed _GraphQL response_.
5458

5559
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
6064
generated or modified by an intermediary. See
6165
[processing a response](#sec-Processing-a-response) for more details.
6266

63-
If the _GraphQL response_ contains a non-null {data} entry then the server must
67+
If the _GraphQL response_ contains a non-null {data} entry then the server MUST
6468
use the `200` status code.
6569

6670
Note: This indicates that no _GraphQL request error_ was raised, though one or
6771
more _GraphQL field error_ may have been raised this is still a successful
6872
execution - see "partial response" in the GraphQL specification.
6973

70-
The server should not use a `4xx` or `5xx` status code for a response to a
74+
The server SHOULD NOT use a `4xx` or `5xx` status code for a response to a
7175
well-formed _GraphQL-over-HTTP request_.
7276

7377
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
7680
strongly discouraged. To use `4xx` and `5xx` status codes in these situations,
7781
please use the `application/graphql-response+json` media type.
7882

79-
If the URL is not used for other purposes, the server should use a `4xx` status
83+
If the URL is not used for other purposes, the server SHOULD use a `4xx` status
8084
code to respond to a request that is not a well-formed _GraphQL-over-HTTP
8185
request_.
8286

@@ -87,20 +91,20 @@ of `2xx` or `5xx` status codes when responding to invalid requests using the
8791
Note: URLs that enable GraphQL requests may enable other types of requests - see
8892
the [URL](#url) section.
8993

90-
#### Examples
94+
### Examples
9195

9296
The following examples provide guidance on how to deal with specific error cases
9397
when using the `application/json` media type to encode the response body:
9498

95-
##### JSON parsing failure
99+
#### JSON parsing failure
96100

97101
For example a POST request body of `NONSENSE` or `{"query":` (note: invalid
98102
JSON).
99103

100104
Requests that the server cannot interpret SHOULD result in status code `400`
101105
(Bad Request).
102106

103-
##### Invalid parameters
107+
#### Invalid parameters
104108

105109
For example a POST request body of `{"qeury": "{__typename}"}` (note: typo) or
106110
`{"query": "query Q ($i:Int!) { q(i: $i) }", "variables": [7]}` (note: invalid
@@ -109,25 +113,25 @@ shape for `variables`).
109113
A request that does not constitute a well-formed _GraphQL-over-HTTP request_
110114
SHOULD result in status code `400` (Bad Request).
111115

112-
##### Document parsing failure
116+
#### Document parsing failure
113117

114118
For example a POST request body of `{"query": "{"}`.
115119

116120
Requests where the _GraphQL document_ cannot be parsed SHOULD result in status
117121
code `200` (Okay).
118122

119-
##### Document validation failure
123+
#### Document validation failure
120124

121125
If a request fails to pass _GraphQL validation_, the server SHOULD NOT execute
122126
the request and SHOULD return a status code of `200` (Okay).
123127

124-
##### Operation cannot be determined
128+
#### Operation cannot be determined
125129

126130
If [GetOperation()](<https://spec.graphql.org/draft/#GetOperation()>) raises a
127131
_GraphQL request error_, the server SHOULD NOT execute the request and SHOULD
128132
return a status code of `200` (Okay).
129133

130-
##### Variable coercion failure
134+
#### Variable coercion failure
131135

132136
If
133137
[CoerceVariableValues()](<https://spec.graphql.org/draft/#CoerceVariableValues()>)
@@ -146,7 +150,7 @@ For example the well-formed GraphQL-over-HTTP request:
146150
would fail variable coercion as the value for `id` would fail to satisfy the
147151
query document's expectation that `id` is non-null.
148152

149-
##### Field errors encountered during execution
153+
#### Field errors encountered during execution
150154

151155
If the operation is executed and no _GraphQL request error_ is raised then the
152156
server SHOULD respond with a status code of `200` (Okay). This is the case even

spec/GraphQLOverHTTP.md

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,8 @@ the `Accept` header.
241241

242242
If the client doesn't know that the server supports
243243
`application/graphql-response+json`, it is RECOMMENDED that the client set the
244-
`Accept` header to `application/graphql-response+json, application/json;q=0.9`.
245-
246-
See [Appendix A](#sec-Appendix-application-json-responses) for more details
244+
`Accept` header to `application/graphql-response+json, application/json;q=0.9`;
245+
see [Appendix A](#sec-Appendix-application-json-responses) for more details
247246
about `application/json` responses.
248247

249248
## GET
@@ -419,6 +418,13 @@ A server MUST indicate the media type of the response with a `Content-Type`
419418
header, and SHOULD indicate the encoding (e.g.
420419
`application/graphql-response+json; charset=utf-8`).
421420

421+
A server MUST support responses using the `application/graphql-response+json`
422+
media type.
423+
424+
:: A _legacy server_ is a _server_ that does not support responses using the
425+
`application/graphql-response+json` media type, and thus does not conform to
426+
this specification.
427+
422428
If an `Accept` header is provided, the server MUST respect the given `Accept`
423429
header and attempt to encode the response in the highest priority media type
424430
listed that is supported by the server.
@@ -428,26 +434,41 @@ In alignment with the
428434
specification, when a client does not include at least one supported media type
429435
in the `Accept` HTTP header, the server MUST either:
430436

437+
1. Disregard the `Accept` header and respond with the server's choice of media
438+
type; OR
431439
1. Respond with a `406 Not Acceptable` status code and stop processing the
432-
request (RECOMMENDED); OR
433-
2. Disregard the `Accept` header and respond with the server's choice of media
434-
type (NOT RECOMMENDED).
440+
request.
441+
442+
If the `Accept` header does not indicate support for
443+
`application/graphql-response+json` but does indicate support for
444+
`application/json`, the server MUST either:
445+
446+
1. Respond with the `application/graphql-response+json` media type
447+
(RECOMMENDED); OR
448+
1. Respond with the `application/json` media type as detailed in
449+
[Appendix A](#sec-Appendix-application-json-responses) (RECOMMENDED if
450+
support for legacy clients is desired); OR
451+
1. Respond with a `406 Not Acceptable` status code and stop processing the
452+
request (NOT RECOMMENDED).
453+
454+
Note: Prior to this specification, the media type `application/json` was in wide
455+
use for the HTTP response payload type. With this media type, clients cannot
456+
trust responses from the server that do not use an HTTP `2xx` status code (since
457+
these replies may come from non-compliant HTTP servers or proxies somewhere in
458+
the request chain), hence the introduction of
459+
`application/graphql-response+json`. Legacy clients, utilities and tooling may
460+
continue to issue `Accept: application/json`, so to maintain interoperability it
461+
is recommended to continue to serve these requests.
462+
463+
If the `Accept` header is present but does not indicate support for any of the
464+
server's supported media types, it is RECOMMENDED to respond with
465+
`406 Not Acceptable`.
435466

436467
Note: It is unlikely that a client can process a response that does not match
437468
one of the media types it has requested, hence `406 Not Acceptable` being the
438469
recommended response. However, the server authors may know better about the
439470
specific clients consuming their endpoint, thus both approaches are permitted.
440471

441-
A GraphQL server MUST support responses using the
442-
`application/graphql-response+json` media type.
443-
444-
For maximal compatibility, a _server_ SHOULD support using both the
445-
`application/json` and the `application/graphql-response+json` media types for
446-
responses.
447-
448-
Note: See [Appendix A](#sec-Appendix-application-json-responses) for more
449-
details about `application/json` responses.
450-
451472
## Validation
452473

453474
Validation of a well-formed _GraphQL-over-HTTP request_ SHOULD apply all the
@@ -474,8 +495,31 @@ execution regardless of validation errors.
474495

475496
In case of errors that completely prevent the generation of a well-formed
476497
_GraphQL response_, the server SHOULD respond with the appropriate status code
477-
depending on the concrete error condition, and MUST NOT respond with a `2xx`
478-
status code.
498+
depending on the concrete error condition.
499+
500+
Otherwise, the status code to use depends on the media type with which the
501+
GraphQL response will be served.
502+
503+
For legacy `application/json` responses, see
504+
[Appendix A](#sec-Appendix-application-json-responses).
505+
506+
### application/graphql-response+json
507+
508+
This section only applies when the response body uses the
509+
`application/graphql-response+json` media type.
510+
511+
Clients should process the response as a well-formed _GraphQL response_
512+
independent of the HTTP status code, and should read the response body
513+
(specifically {data} and {errors}) to determine the status of the response.
514+
515+
Note: With `application/graphql-response+json`, clients know the response is
516+
well formed and should determine the detailed status of the response from the
517+
response body alone, allowing server authors to adopt more appropriate status
518+
codes without impacting behavior of existing clients. Intermediary servers may
519+
use the status code to determine the status of the _GraphQL response_ without
520+
needing to process the response body; this is useful in request logs, developer
521+
tooling, anomaly and intrusion detection, metrics and observability, API
522+
gateways, and more.
479523

480524
If the _GraphQL response_ contains the {data} entry and it is not {null}, then
481525
the server MUST reply with a `2xx` status code.

0 commit comments

Comments
 (0)