Skip to content

Commit b50a0c6

Browse files
authored
Move all the application/json content to a non-normative note (#372)
* Remove the security note, we have a non-normative note now * remove the table from the media types * Add compatibility non-normative note * Focus on JSON * Do not repeat ourselves * Be explicit that null or absent is equivalent to an empty map * Move Accept compatibility to compatibility section * no exception for the empty string * move POST null parameters outside of a note, this is normative * consistency * Move the "ignore unknown keys" above because it applies to both GET and POST * Move the 'null' references to the POST section. It doesn't make much sense for GET * move the GET requests MUST not be mutations above examples * Add another example for GET. Keep GET and POST sections symmetrical * 200 is not necessarily good? * move down * Add application/json media type * format * formating * Do not use uppercase in non-normative notes * Move all status code requirements to the status code section * Add an extra sentence to help with the reading flow
1 parent fceb342 commit b50a0c6

1 file changed

Lines changed: 135 additions & 123 deletions

File tree

spec/GraphQLOverHTTP.md

Lines changed: 135 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,6 @@ The [GraphQL specification](https://spec.graphql.org) deliberately does not
2424
specify the transport layer; however, HTTP is the most common choice when
2525
serving GraphQL to remote clients due to its ubiquity.
2626

27-
Previous to this specification, the article
28-
[Serving over HTTP](https://graphql.org/learn/serving-over-http)
29-
([WayBack Machine entry, 1st June 2022](https://web.archive.org/web/20220601155421/https://graphql.org/learn/serving-over-http))
30-
on the graphql.org website served as guidance, and leading implementations on
31-
both client and server have mostly upheld those best practices and thus
32-
established a de-facto standard that is commonly used throughout the ecosystem.
33-
This specification aims to codify and expand on this work.
34-
3527
**Copyright notice**
3628

3729
Copyright © 2022-present, GraphQL contributors
@@ -162,33 +154,16 @@ http://example.com/product/graphql
162154

163155
# Serialization Format
164156

165-
The GraphQL specification allows for many
166-
[serialization formats to be implemented](https://spec.graphql.org/draft/#sec-Serialization-Format).
167-
Servers and clients MUST support JSON and MAY support other, additional
168-
serialization formats.
169-
170-
Note: Allowing other media types, particularly on requests, can be insecure.
171-
172-
For consistency and ease of notation, examples of the response are given in JSON
173-
throughout this specification.
157+
Servers and clients MUST support JSON as a serialization format.
174158

175159
## Media Types
176160

177-
The following are the officially recognized GraphQL media types to designate
178-
using the JSON encoding for GraphQL requests:
161+
The following are the officially recognized GraphQL media types:
179162

180-
| Name | Description |
181-
| ------------------ | --------------------------------------- |
182-
| `application/json` | Standard type for GraphQL JSON requests |
183-
184-
And for a _GraphQL response_:
185-
186-
| Name | Description |
187-
| ----------------------------------- | --------------------------------------- |
188-
| `application/graphql-response+json` | The preferred type for server responses |
189-
190-
Note: Servers MAY additionally support `application/json` as a response media
191-
type.
163+
| Name | Description |
164+
| ----------------------------------- | ------------------------------------- |
165+
| `application/json` | Media type for GraphQL JSON requests |
166+
| `application/graphql-response+json` | Media type for GraphQL JSON responses |
192167

193168
For details of the shapes of these JSON payloads, please see
194169
[Request](#sec-Request) and [Response](#sec-Response).
@@ -220,6 +195,13 @@ parameters in one of the manners described in this specification:
220195
extend the protocol however they see fit, as specified in
221196
[the Response section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Response-Format.Response).
222197

198+
Servers receiving a request with additional properties MUST ignore properties
199+
they do not understand.
200+
201+
If implementers need to add additional information to a request they MUST do so
202+
via other means; the RECOMMENDED approach is to add an implementer-scoped entry
203+
to the {extensions} object.
204+
223205
Note: When comparing _GraphQL-over-HTTP request_ against the term
224206
["request"](https://spec.graphql.org/draft/#request) in the GraphQL
225207
specification you should note the _GraphQL schema_ and "initial value" are not
@@ -231,17 +213,6 @@ string describing one or more operations, each of which may be a query or
231213
mutation. A better name would have been `document`, but the term `query` is well
232214
established.
233215

234-
Note: Depending on the serialization format used, values of the aforementioned
235-
parameters can be encoded differently but their names and semantics must stay
236-
the same.
237-
238-
Note: An HTTP request that encodes parameters of the same names but of the wrong
239-
type, or that omits required parameters, is not a well-formed _GraphQL-over-HTTP
240-
request_.
241-
242-
Note: Specifying `null` for optional request parameters is equivalent to not
243-
specifying them at all.
244-
245216
Note: So long as it is a string, {query} does not have to parse or validate to
246217
be part of a well-formed _GraphQL-over-HTTP request_.
247218

@@ -254,10 +225,6 @@ A client MUST indicate the media types that it supports in responses using the
254225
The client MUST include the media type `application/graphql-response+json` in
255226
the `Accept` header.
256227

257-
The client MAY additionally include the media type `application/json` in the
258-
`Accept` header. When accepting both media types, the client SHOULD indicate it
259-
prefers `application/graphql-response+json` over `application/json`.
260-
261228
## GET
262229

263230
For HTTP GET requests, the _GraphQL-over-HTTP request_ parameters MUST be
@@ -269,26 +236,30 @@ The {query} parameter MUST be the string representation of the source text of
269236
the document as specified in
270237
[the Language section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Language).
271238

272-
The {operationName} parameter, if present, must be a string.
239+
The {operationName} parameter, if present and not the empty string, MUST be a
240+
string.
273241

274-
Each of the {variables} and {extensions} parameters, if used, MUST be encoded as
275-
a JSON string.
242+
Each of the {variables} and {extensions} parameters, if present, MUST be encoded
243+
as a JSON object string.
276244

277-
The {operationName} parameter, if supplied and not the empty string, represents
245+
For robustness, specifying the empty string for optional request parameters is
246+
equivalent to not specifying them at all.
247+
248+
The {operationName} parameter, if present and not the empty string, represents
278249
the name of the operation to be executed within the {query} as a string.
279250

251+
GET requests MUST NOT be used for executing mutation operations. This
252+
restriction is necessary to conform with the long-established semantics of safe
253+
methods within HTTP.
254+
280255
Note: In the final URL all of these parameters will appear in the query
281256
component of the request URL as URL-encoded values due to the WHATWG
282257
URLSearchParams encoding specified above.
283258

284-
Setting the value of the {operationName} parameter to the empty string is
285-
equivalent to omitting the {operationName} parameter.
286-
287259
Note: By the above, `operationName=null` represents an operation with the name
288-
`"null"` (such as `query null { __typename }`). If a literal `null` is desired,
289-
either omit {operationName} or set it to the empty string.
260+
`"null"` (such as `query null { __typename }`).
290261

291-
### Example
262+
### Examples
292263

293264
If we wanted to execute the following GraphQL query:
294265

@@ -308,18 +279,29 @@ This request could be sent via an HTTP GET as follows:
308279
http://example.com/graphql?query=query(%24id%3A%20ID!)%7Buser(id%3A%24id)%7Bname%7D%7D&variables=%7B%22id%22%3A%22QVBJcy5ndXJ1%22%7D
309280
```
310281

311-
GET requests MUST NOT be used for executing mutation operations. If the values
312-
of {query} and {operationName} indicate that a mutation operation is to be
313-
executed, the server MUST respond with error status code `405` (Method Not
314-
Allowed) and halt execution. This restriction is necessary to conform with the
315-
long-established semantics of safe methods within HTTP.
282+
An empty {operationName} is allowed. This is a valid request:
283+
284+
```url example
285+
http://example.com/graphql?query=%7B%20foo%20%7D&operationName=
286+
```
316287

317288
## POST
318289

319-
A GraphQL POST request instructs the server to perform a query or mutation
320-
operation. A GraphQL POST request MUST have a body which contains values of the
321-
_GraphQL-over-HTTP request_ parameters encoded in one of the officially
322-
recognized GraphQL media types, or another media type supported by the server.
290+
A GraphQL POST request MUST have a body which contains values of the
291+
_GraphQL-over-HTTP request_ parameters encoded using the `application/json`
292+
media type.
293+
294+
The {query} parameter MUST be the string representation of the source text of
295+
the document as specified in
296+
[the Language section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Language).
297+
298+
The {operationName} parameter, if present and not null, MUST be a string.
299+
300+
Each of the {variables} and {extensions} parameters, if present and not null,
301+
MUST be a JSON object.
302+
303+
For robustness, specifying null for optional request parameters is equivalent to
304+
not specifying them at all.
323305

324306
A client MUST indicate the media type of a request body using the `Content-Type`
325307
header as specified in [RFC7231](https://datatracker.ietf.org/doc/html/rfc7231).
@@ -333,43 +315,15 @@ indicating an encoding, the server MUST assume the encoding is `utf-8`.
333315
If the client does not supply a `Content-Type` header with a POST request, the
334316
server SHOULD reject the request using the appropriate `4xx` status code.
335317

318+
If the values of {query} and {operationName} indicate that a mutation operation
319+
is to be executed with a GET request, the server MUST respond with error status
320+
code `405` (Method Not Allowed) and halt execution.
321+
336322
Note: Rejecting such requests encourages clients to supply a `Content-Type`
337323
header with every POST request. A server has the option to assume any media type
338324
they wish when none is supplied, with the understanding that parsing the request
339325
may fail.
340326

341-
A server MAY support POST requests encoded with and/or accepting other media
342-
types or encodings.
343-
344-
If a client does not know the media types the server supports then it SHOULD
345-
encode the request body in JSON (i.e. with `Content-Type: application/json`).
346-
347-
Note: Request encoding with media type `application/json` is supported by every
348-
compliant _server_.
349-
350-
### JSON Encoding
351-
352-
When encoded in JSON, a _GraphQL-over-HTTP request_ is encoded as a JSON object
353-
(map), with the properties specified by the GraphQL-over-HTTP request:
354-
355-
- {query} - the string representation of the Source Text of the Document as
356-
specified in
357-
[the Language section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Language).
358-
- {operationName} - an optional string
359-
- {variables} - an optional object (map), the keys of which are the variable
360-
names and the values of which are the variable values
361-
- {extensions} - an optional object (map) reserved for implementers to extend
362-
the protocol however they see fit, as specified in
363-
[the Response section of the GraphQL specification](https://spec.graphql.org/draft/#sec-Response-Format.Response).
364-
365-
All other property names are reserved for future expansion. If implementers need
366-
to add additional information to a request they MUST do so via other means; the
367-
RECOMMENDED approach is to add an implementer-scoped entry to the {extensions}
368-
object.
369-
370-
Servers receiving a request with additional properties MUST ignore properties
371-
they do not understand.
372-
373327
### Example
374328

375329
If we wanted to execute the following GraphQL query:
@@ -413,8 +367,8 @@ And the body:
413367

414368
When a server receives a well-formed _GraphQL-over-HTTP request_, it must return
415369
a well‐formed _GraphQL response_. The server's response describes the result of
416-
validating and executing the requested operation if successful, and describes
417-
any errors encountered during the request.
370+
validating and executing the requested operation if successful and describes any
371+
errors encountered during the request.
418372

419373
A server must comply with
420374
[RFC7231](https://datatracker.ietf.org/doc/html/rfc7231).
@@ -424,14 +378,19 @@ A server must comply with
424378
The body of the server's response MUST follow the requirements for a _GraphQL
425379
response_, encoded directly in the chosen media type.
426380

427-
A server MUST indicate the media type of the response with a `Content-Type`
428-
header, and SHOULD indicate the encoding (e.g.
429-
`application/graphql-response+json; charset=utf-8`).
430-
431381
If an `Accept` header is provided, the server MUST respect the given `Accept`
432382
header and attempt to encode the response in the highest priority media type
433383
listed that is supported by the server.
434384

385+
A _server_ MUST support responses using the `application/graphql-response+json`
386+
media type.
387+
388+
A server MAY additionally support other response media types.
389+
390+
A server MUST indicate the media type of the response with a `Content-Type`
391+
header, and SHOULD indicate the encoding (e.g.
392+
`application/graphql-response+json; charset=utf-8`).
393+
435394
In alignment with the
436395
[HTTP 1.1 Accept](https://tools.ietf.org/html/rfc7231#section-5.3.2)
437396
specification, when a client does not include at least one supported media type
@@ -447,15 +406,6 @@ one of the media types it has requested, hence `406 Not Acceptable` being the
447406
recommended response. However, the server authors may know better about the
448407
specific clients consuming their endpoint, thus both approaches are permitted.
449408

450-
A _server_ MUST support responses using the `application/graphql-response+json`
451-
media type.
452-
453-
A server MAY additionally support the `application/json` response media type.
454-
455-
Note: Servers may wish to only support the `application/graphql-response+json`
456-
media type so that related HTTP tooling may utilize the HTTP status codes of
457-
responses without having to be GraphQL-aware.
458-
459409
## Validation
460410

461411
Validation of a well-formed _GraphQL-over-HTTP request_ SHOULD apply all the
@@ -478,7 +428,7 @@ should not be executed; however in certain circumstances, for example persisted
478428
operations that were previously known to be valid, the server may attempt
479429
execution regardless of validation errors.
480430

481-
## Status Codes
431+
## Status Code
482432

483433
In case of errors that completely prevent the generation of a well-formed
484434
_GraphQL response_, the server MUST respond with the appropriate status code
@@ -488,8 +438,7 @@ status code.
488438
Note: Typically the appropriate status code will be `400` (Bad Request).
489439

490440
If the _GraphQL response_ contains the {data} entry and it is not {null}, then
491-
the server MUST reply with a `2xx` status code and SHOULD reply with `200`
492-
status code.
441+
the server MUST reply with a `2xx` status code.
493442

494443
Note: The result of executing a GraphQL operation may contain partial data as
495444
well as encountered errors. Errors that happen during execution of the GraphQL
@@ -504,12 +453,12 @@ are expected to be supported over time, valid codes must be present in this
504453
document.
505454

506455
If the _GraphQL response_ contains the {data} entry and it is {null}, then the
507-
server SHOULD reply with a `2xx` status code and it is RECOMMENDED it replies
508-
with `200` status code.
456+
server SHOULD reply with a `2xx` status code.
509457

510458
Note: Using `4xx` and `5xx` status codes in this situation is not recommended -
511459
since no _GraphQL request error_ has occurred it is seen as a "partial
512-
response".
460+
response". This is typically the case if an error is propagated to the root
461+
field.
513462

514463
If the _GraphQL response_ does not contain the {data} entry then the server MUST
515464
reply with a `4xx` or `5xx` status code as appropriate.
@@ -524,11 +473,6 @@ pass validation, then the server SHOULD reply with `400` status code.
524473
If the client is not permitted to issue the GraphQL request then the server
525474
SHOULD reply with `403`, `401` or similar appropriate status code.
526475

527-
Note: Clients can rely on the response being a well-formed _GraphQL response_
528-
regardless of the status code. Intermediary servers may use the status code to
529-
determine the status of the _GraphQL response_ without needing to process the
530-
response body.
531-
532476
### Examples
533477

534478
The following examples provide guidance on how to deal with specific error
@@ -600,6 +544,74 @@ response; it still indicates successful execution.
600544
This section of the specification is non-normative, even where the words and
601545
phrases specified in RFC2119 are used.
602546

547+
## application/json response media type
548+
549+
Previous to this specification, the article
550+
[Serving over HTTP](https://graphql.org/learn/serving-over-http)
551+
([WayBack Machine entry, 1st June 2022](https://web.archive.org/web/20220601155421/https://graphql.org/learn/serving-over-http))
552+
on the graphql.org website served as guidance.
553+
554+
This article used `application/json` as media type for the response.
555+
556+
In some cases, the response received by a client may not originate from a
557+
GraphQL service, but instead from an intermediary—such as an API gateway, proxy,
558+
firewall or other middleware—that does not implement this specification. Such an
559+
intermediary might produce the response to indicate an error, returning a
560+
response with `4xx` or `5xx` status code and potentially using the standard
561+
`application/json` media type to encode the reason for the error. Such a
562+
response is unlikely to be a valid GraphQL response.
563+
564+
For this reason, a client application receiving an `application/json` response,
565+
could rely on the response being a well-formed _GraphQL response_ only if the
566+
status code is `200`.
567+
568+
This caused multiple observability issues because it was challenging to
569+
distinguish a well-formed _GraphQL response_ from an intermediary response.
570+
571+
`application/graphql-response+json` allows to distringuish a well-formed
572+
_GraphQL response_ from another intermediary response and is the required media
573+
type moving forward.
574+
575+
For compatibility reasons, clients and servers may support `application/json` as
576+
described in this section.
577+
578+
Note: Servers may wish to only support the `application/graphql-response+json`
579+
media type so that related HTTP tooling may utilize the HTTP status codes of
580+
responses without having to be GraphQL-aware.
581+
582+
### Accept
583+
584+
To maximize compatibility, a client may include the media type
585+
`application/json` in the `Accept` header. When doing this, it is recommended
586+
that the client set the `Accept` header to
587+
`application/graphql-response+json, application/json;q=0.9`.
588+
589+
Note: The `q=0.9` parameter tells content negotiation that `application/json`
590+
should only be used if `application/graphql-response+json` is not supported.
591+
592+
### Status code
593+
594+
When using the `application/json` media type, the server should use the `200`
595+
status code for every response to a well-formed _GraphQL-over-HTTP request_,
596+
independent of any _GraphQL request error_ or _GraphQL field error_ raised.
597+
598+
If the response uses a non-`200` status code then the client must not rely on
599+
the body to be a well-formed _GraphQL response_.
600+
601+
If the _GraphQL response_ contains a non-null {data} entry then the server must
602+
use the `200` status code.
603+
604+
Note: This indicates that no _GraphQL request error_ was raised, though one or
605+
more _GraphQL field error_ may have been raised this is still a successful
606+
execution - see "partial response" in the GraphQL specification.
607+
608+
The server should not use a `4xx` or `5xx` status code for a response to a
609+
well-formed _GraphQL-over-HTTP request_.
610+
611+
If the URL is not used for other purposes, the server should use a `4xx` status
612+
code to respond to a request that is not a well-formed _GraphQL-over-HTTP
613+
request_.
614+
603615
## Security
604616

605617
This specification focuses solely on the intersection of GraphQL and HTTP.

0 commit comments

Comments
 (0)