diff --git a/cspell.yml b/cspell.yml index eb0eacbd..d49037c6 100644 --- a/cspell.yml +++ b/cspell.yml @@ -6,6 +6,7 @@ words: # Terms of art - roadmap - endianness + - cacheable - interoperation - monospace - openwebfoundation diff --git a/spec/GraphQLOverHTTP.md b/spec/GraphQLOverHTTP.md index ef1b1045..e5b15e3f 100644 --- a/spec/GraphQLOverHTTP.md +++ b/spec/GraphQLOverHTTP.md @@ -181,8 +181,9 @@ assumed). # Request -A server MUST support _GraphQL-over-HTTP request_ via `POST`, and MAY support -_GraphQL-over-HTTP request_ via other HTTP methods, such as `GET`. +A server MUST support _GraphQL-over-HTTP request_ via `POST`, SHOULD support +_GraphQL-over-HTTP request_ via `QUERY`, and MAY support _GraphQL-over-HTTP +request_ via other HTTP methods, such as `GET`. ## GraphQL-over-HTTP Request @@ -307,9 +308,14 @@ http://example.com/graphql?query=query(%24id%3A%20ID!)%7Buser(id%3A%24id)%7Bname ## POST A POST request instructs the GraphQL-over-HTTP server to perform a query or -mutation operation. The 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. +mutation operation. + +Note: when possible, it is recommended to perform query operations using +idempotent and cacheable QUERY requests instead of POST requests. + +The 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 client MUST indicate the media type of a request body using the `Content-Type` header; this header is specified in @@ -403,6 +409,76 @@ And the body: } ``` +## QUERY + +A [QUERY](https://httpwg.org/specs/rfc10008.html) request instructs the +GraphQL-over-HTTP server to perform a query operation. The 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. + +As stated in [IETF RFC 10008](https://httpwg.org/specs/rfc10008.html#query) a +client MUST indicate the media type of a request body using the `Content-Type` +header; this header is specified in +[IETF RFC 9110](https://httpwg.org/specs/rfc9110.html#field.accept). + +If a server supports QUERY requests, it MUST support QUERY requests using the +`application/json` media type (as indicated by the `Content-Type` header) +encoded with UTF-8. + +A server SHOULD indicate it supports QUERY using the HTTP semantics, as +indicated in the +[IETF RFC 10008](https://httpwg.org/specs/rfc10008.html#example.discovery.method). + +For QUERY requests using an officially recognized GraphQL `Content-Type` without +indicating an encoding, the server MUST assume the encoding is `utf-8`. + +If the client does not supply a `Content-Type` header with a QUERY request, the +server SHOULD reject the request using the appropriate `4xx` status code. + +Note: Rejecting such requests encourages clients to supply a `Content-Type` +header with every QUERY 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 QUERY 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`). + +QUERY 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 `422` (Unprocessable +Entity) and halt execution. This restriction is necessary to conform with the +long-established semantics of safe methods within HTTP. + +### 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. + +Servers receiving a request with additional properties MUST ignore properties +they do not understand. + +Specifying `null` for optional request parameters is equivalent to not +specifying them at all. + # Response When a server receives a well-formed _GraphQL-over-HTTP request_, it must return @@ -552,6 +628,8 @@ _GraphQL request error result_ and the server MUST reply with an appropriate status code should be used: - If a mutation is attempted via the `GET` verb, status code `405` SHOULD be used. + - If a mutation is attempted via the `QUERY` verb, status code `422` SHOULD be + used. - If the request uses an unsupported HTTP method, status code `405` SHOULD be used. - If the `Content-Type` of the request is not supported, status code `415` @@ -562,7 +640,7 @@ _GraphQL request error result_ and the server MUST reply with an appropriate - If the client did not produce a request within the time that the server was prepared to wait, status code `408` SHOULD be used. - If the size of the URI was too large, status code `414` SHOULD be used (and - the client should consider using `POST` instead). + the client should consider using `POST` or `QUERY` instead). - If the size of the request headers (or any one header) was too large, status code `431` SHOULD be used. - If the size of the `POST` request body was too large, status code `413`