Note: Stage 2: Draft — this spec is not yet official, but is now a fully formed solution. Drafts may continue to evolve and change, occasionally dramatically, and are not guaranteed to be accepted. Therefore, it is unwise to rely on a draft in a production GraphQL Service.
Introduction
This specification details how GraphQL should be served and consumed over HTTP in order to maximize interoperability between clients, servers and tools. This specification does not override or replace the GraphQL specification; it extends it to cover the topic of serving GraphQL services over HTTP. If any statement or algorithm in this specification appears to conflict with the GraphQL specification, the behavior detailed in the GraphQL specification should be used (and an issue raised).
The GraphQL specification deliberately does not specify the transport layer; however, HTTP is the most common choice when serving GraphQL to remote clients due to its ubiquity.
Copyright notice
Copyright © 2022-present, GraphQL contributors
THESE MATERIALS ARE PROVIDED “AS IS”. The parties expressly disclaim any warranties (express, implied, or otherwise), including implied warranties of merchantability, non-infringement, fitness for a particular purpose, or title, related to the materials. The entire risk as to implementing or otherwise using the materials is assumed by the implementer and user. IN NO EVENT WILL THE PARTIES BE LIABLE TO ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES OF ACTION OF ANY KIND WITH RESPECT TO THIS DELIVERABLE OR ITS GOVERNING AGREEMENT, WHETHER BASED ON BREACH OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, AND WHETHER OR NOT THE OTHER MEMBER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Conformance
A conforming implementation of GraphQL over HTTP must fulfill all normative requirements. Conformance requirements are described in this document via both descriptive assertions and key words with clearly defined meanings.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the normative portions of this document are to be interpreted as described in IETF RFC 2119. These key words may appear in lowercase and still retain their meaning unless explicitly declared as non-normative.
A conforming implementation of GraphQL over HTTP may provide additional functionality, but must not where explicitly disallowed or would otherwise result in non-conformance.
Non-Normative Portions
All contents of this document are normative except portions explicitly declared as non-normative.
Examples in this document are non-normative, and are presented to aid understanding of introduced concepts and the behavior of normative portions of the specification. Examples are either introduced explicitly in prose (e.g. "for example") or are set apart in example or counter-example blocks, like this:
This is an example of a non-normative example.
This is an example of a non-normative counter-example.
Notes in this document are non-normative, and are presented to clarify intent, draw attention to potential edge-cases and pit-falls, and answer common questions that arise during implementation. Notes are either introduced explicitly in prose (e.g. "Note: ") or are set apart in a note block, like this:
Note: This is an example of a non-normative note.
Though the GraphQL specification is transport agnostic, this GraphQL over HTTP specification aims to map GraphQL's semantics to their HTTP equivalents, enabling us to combine the full advantages of GraphQL with the rich feature set of HTTP.
GraphQL queries and mutations naturally mirror the request/response message model used in HTTP, allowing us to provide a GraphQL request in an HTTP request and a GraphQL response in an HTTP response.
:: In this document, the term server refers to a GraphQL over HTTP Specification compliant HTTP server unless the context indicates otherwise.
The role of a server is to provide a client access to one or more GraphQL services over HTTP. A server is not a GraphQL service; it is a GraphQL service host.
:: In this document, the term client refers to a GraphQL over HTTP Specification compliant HTTP client unless the context indicates otherwise.
The role of a client is to issue HTTP requests to a server in order to interact with a GraphQL service.
Note: GraphQL Subscriptions are beyond the scope of this specification at this time.
A server MUST enable GraphQL requests to one or more GraphQL schemas.
Each GraphQL schema a server provides MUST be served via one or more URLs.
The GraphQL schema available via a single URL MAY be different for different clients. For example, alpha testers or authenticated users may have access to a schema with additional fields.
A server MAY forbid individual requests by a client to any endpoint for any
reason, for example to require authentication or payment; when doing so it
SHOULD use the relevant 4xx or 5xx status code. This decision SHOULD NOT be
based on the contents of a well-formed GraphQL-over-HTTP request.
Note: The server should not make authorization decisions based on any part of the GraphQL request; these decisions should be made by the GraphQL schema during GraphQL's ExecuteRequest(), allowing for a partial response to be generated.
Server URLs which enable GraphQL requests MAY also be used for other purposes, as long as they don't conflict with the server's responsibility to handle GraphQL requests.
It is RECOMMENDED to end the path component of the URL with /graphql, for
example:
http://example.com/graphqlhttp://product.example.com/graphqlhttp://example.com/product/graphqlThe GraphQL specification allows for many serialization formats to be implemented. 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.
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 |
For details of the shapes of these JSON payloads, please see Request and Response.
If the media type in a Content-Type or Accept header does not include
encoding information and matches one of the officially recognized GraphQL media
types, then utf-8 MUST be assumed (e.g. for header
Content-Type: application/graphql-response+json, UTF-8 encoding would be
assumed).
A server MUST accept POST requests, and MAY accept other HTTP methods, such as GET.
:: A GraphQL-over-HTTP request is an HTTP request that encodes the following parameters in one of the manners described in this specification:
- {query} - (Required, string): The string representation of the Source Text of a GraphQL Document as specified in the Language section of the GraphQL specification.
- {operationName} - (Optional, string): The name of the Operation in the Document to execute.
- {variables} - (Optional, map): Values for any Variables defined by the Operation.
- {extensions} - (Optional, map): This entry is reserved for implementers to extend the protocol however they see fit, as specified in the Response section of the GraphQL specification.
Note: When comparing GraphQL-over-HTTP request against the term "request" in the GraphQL specification you should note the GraphQL schema and "initial value" are not included in the GraphQL-over-HTTP request; they are handled by the server based on the URL used.
Note: Be aware that query is a misleading parameter name as its value is a
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.
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.
A client MUST indicate the media types that it supports in responses using the
Accept HTTP header as specified in
RFC7231.
Note: If a client does not supply the Accept header then the server may
respond with an error, or with any content type it chooses (including serving a
valid GraphQL response under a media type of its choosing). To ensure your
client gets something useful, it needs to indicate the media types it supports.
The client MUST include the media type application/graphql-response+json in
the Accept header.
:: A legacy client is a client that does not support responses using the
application/graphql-response+json media type, and thus does not conform to
this specification.
If it is not known that the server supports application/graphql-response+json,
it is RECOMMENDED that the client set the Accept header to
application/graphql-response+json, application/json;q=0.9.
For HTTP GET requests, the GraphQL-over-HTTP request parameters MUST be
provided in the query component of the request URL, encoded in the
application/x-www-form-urlencoded format as specified by the
WHATWG URLSearchParams class.
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.
The {operationName} parameter, if present, must be a string.
Each of the {variables} and {extensions} parameters, if present and not the empty string, MUST be encoded as a JSON string.
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.
Specifying the empty string for optional request parameters is equivalent to not specifying them at all.
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.
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.
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.
If we wanted to execute the following GraphQL query:
query($id: ID!){user(id:$id){name}}
With the following query variables:
{"id":"QVBJcy5ndXJ1"}
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%7DA 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.
A client MUST indicate the media type of a request body using the Content-Type
header as specified in RFC7231.
A server MUST support POST requests encoded with the application/json media
type (as indicated by the Content-Type header) encoded with UTF-8.
For POST 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 POST 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 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.
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.
- {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.
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.
If we wanted to execute the following GraphQL query:
query ($id: ID!) {
user(id: $id) {
name
}
}
With the following query variables:
{
"id": "QVBJcy5ndXJ1"
}This request could be sent via an HTTP POST to the relevant URL using the JSON encoding with the headers:
Content-Type: application/json
Accept: application/graphql-response+json
And the body:
{
"query": "query ($id: ID!) {\n user(id: $id) {\n name\n }\n}",
"variables": {
"id": "QVBJcy5ndXJ1"
}
}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.
A server must comply with RFC7231.
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).
A server MUST support responses using the application/graphql-response+json
media type.
:: A legacy server is a server that does not support responses using the
application/graphql-response+json media type, and thus does not conform to
this specification.
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.
In alignment with the
HTTP 1.1 Accept
specification, when a client does not include at least one supported media type
in the Accept HTTP header, the server MUST either:
- Respond with a
406 Not Acceptablestatus code and stop processing the request; OR - Disregard the
Acceptheader and respond with the server's choice of media type.
If the Accept header does not indicate support for one of the server's
preferred media types but does indicate support for application/json, as may
be the case for a legacy client, it is RECOMMENDED to perform the request
following the requirements of this specification as if the request had specified
Accept: application/graphql-response+json, except any response that produces a
2xx status code should replace the Content-Type header with
Content-Type: application/json.
Note: This recommendation uses this specification's full range of HTTP status
codes whilst maximizing legacy client compatibility for successful and
partially successful requests. HTTP responses could originate from non-GraphQL
intermediary servers and middleware handling failures (HTTP 4xx and 5xx), so
clients typically can only rely on a response to be from GraphQL either when it
is successful (HTTP 2xx) or when it explicitly declares it is a GraphQL
response (Content-Type: application/graphql-response+json).
If the Accept header is present but does not indicate support for any of the
server's supported media types or application/json, it is RECOMMENDED to
respond with 406 Not Acceptable.
Note: It is unlikely that a client can process a response that does not match
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.
Validation of a well-formed GraphQL-over-HTTP request SHOULD apply all the validation rules specified by the GraphQL specification.
The server MAY, at its discretion, apply additional validation rules.
Note: Examples of additional validation rules the server may apply include depth limit, complexity limit, etc.
Execution of a GraphQL-over-HTTP request follows GraphQL's ExecuteRequest() algorithm.
Note: In general, a GraphQL-over-HTTP request that does not pass validation 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.
Clients should process a response using the application/graphql-response+json
media type as a well-formed GraphQL response independent of the HTTP status
code.
Note: With application/graphql-response+json, clients know the response is
well-formed and should determine the detailed status of the response from the
response body alone, allowing server authors to adopt more appropriate status
codes without impacting behavior of existing clients. Intermediary servers and
services may use the status code to determine the status of the GraphQL
response without needing to process the response body; this is useful in
request logs, developer tooling, anomaly and intrusion detection, metrics and
observability, API gateways, and more.
In case of errors that completely prevent the generation of a well-formed
GraphQL response, the server SHOULD respond with the appropriate HTTP 4xx or
5xx status code depending on the concrete error condition, and MUST NOT use
the application/graphql-response+json media type.
If the GraphQL response contains the {data} entry and it is not {null}, then
the server MUST reply with a 2xx status code.
If the GraphQL response contains the {data} entry and does not contain the
{errors} entry, then the server SHOULD reply with a 200 status code.
Note: There are no circumstances where the GraphQL specification allows for a response having {data} as {null} without {errors} being present.
If the GraphQL response contains both the {data} entry (even if it is {null})
and the {errors} entry, then the server SHOULD reply with a 294 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
operation typically become part of the result, as long as the server is still
able to produce a well-formed GraphQL response. For details of why status code
294 is recommended, see Partial success. Using 4xx
and 5xx status codes in this situation is not appropriate: since no GraphQL
request error has occurred it is seen as a "partial response" or "partial
success".
If the GraphQL response does not contain the {data} entry then the server MUST
reply with an appropriate 4xx or 5xx status code:
- If the failure is due to an issue in the request itself, the appropriate
4xxstatus code should be used:- If a mutation is attempted via the
GETverb, status code405MUST be used. - If an unsupported HTTP method is used, status code
405is RECOMMENDED. - If the
Content-Typeof the request is not supported, status code415is RECOMMENDED. - If none of the media types in the
Acceptheader are supported and theAcceptheader does not includeapplication/json, then status code406is RECOMMENDED. - If the client did not produce a request within the time that the server was
prepared to wait, status code
408is RECOMMENDED. - If the size of the URI was too large, status code
414is RECOMMENDED (and the client should consider usingPOSTinstead). - If the size of the request headers (or any one header) was too large, status
code
431is RECOMMENDED. - If the size of the
POSTrequest body was too large, status code413is RECOMMENDED. - If the JSON body of the request could not be parsed, status code
400is RECOMMENDED. - If the request is not a well-formed GraphQL-over-HTTP request, status code
422is RECOMMENDED. - If the GraphQL document in the request cannot be parsed, status code
400is RECOMMENDED. - If the request does not pass GraphQL validation, status code
422is RECOMMENDED. - If the operation to execute cannot be unambiguously determined, status code
422is RECOMMENDED. - If the variable values cannot be coerced to match the operation's variable
definitions, status code
422is RECOMMENDED. - If the client is not permitted to issue the GraphQL request, then the server
SHOULD reply with
401,403or similar appropriate status code. - If the server cannot process the request due to being a short and stout
ceramic vessel, status code
418is RECOMMENDED.
- If a mutation is attempted via the
- When the server is the reason for failure, the appropriate
5xxstatus code should be used. For example, if the server is not able to execute requests at this time due to maintenance or load-shedding, then status code503is RECOMMENDED.
Note: The GraphQL specification indicates that the only situation in which the GraphQL response does not include the {data} entry is one in which the {errors} entry is populated.
The following examples provide guidance on how to deal with specific error cases:
JSON parsing failure
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).
Invalid parameters
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 422 (Unprocessable Content).
Document parsing failure
For example, a POST request body of {"query": "{"}.
Requests where the GraphQL document cannot be parsed should result in status
code 400 (Bad Request).
Document validation failure
If a request fails GraphQL validation, the server SHOULD return a status code
of 422 (Unprocessable Content) without proceeding to GraphQL execution.
Operation cannot be determined
If GetOperation() raises a
GraphQL request error, the server SHOULD NOT execute the request and SHOULD
return a status code of 422 (Unprocessable Content).
Variable coercion failure
If
CoerceVariableValues()
raises a GraphQL request error, the server SHOULD NOT execute the request and
SHOULD return a status code of 422 (Unprocessable Content).
Field errors encountered during execution
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().
Note: The GraphQL specification differentiates field errors from request errors and refers to the situation wherein a GraphQL field error occurs as a partial 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.
The result of executing a GraphQL operation may contain partial data as well as encountered errors. Errors that happen during execution of the GraphQL operation typically become part of the result, as long as the server is still able to produce a well-formed GraphQL response.
Using 4xx and 5xx status codes when {data} is present and non-null is not
appropriate; since no GraphQL request error has occurred it is seen as a
"partial response" or "partial success".
There's currently not an approved official HTTP status code to use for a
"partial success". Contenders include "203 Non-Authoritative information" (which
indicates the response has been transformed), "206 Partial Content" (which
requires the Range header), and WebDAV's status code "207 Multi-Status" (which
"provides status for multiple independent operations"). None of those quite
fit GraphQL's needs, so we recommend using custom code "294 Partial Success".
Since we are defining the code ourselves, rather than the IETF, we only
recommend its usage alongside the application/graphql-response+json media type
which makes the meaning explicit.
Note: This status code is not to help clients, who should ignore the status code
of a response when receiving the application/graphql-response+json media type,
but allows servers to indicate partial success such that intermediaries that do
not implement this specification may still track the not-fully-successful
request (for example, for observability).
This specification focuses solely on the intersection of GraphQL and HTTP. General concerns of either technology, including security concerns, are out of scope, except where their interaction introduces additional considerations.
Implementers are expected to have a solid understanding of the security
implications of exposing a service over HTTP, and are responsible for
implementing relevant mitigations and solutions. This specification will not
repeat standard HTTP best practices such as not using GET for requests with
side effects, safe logging of requests without revealing sensitive information,
ensuring all connections are encrypted via HTTPS, placing limits on the length
of incoming data, implementing rate limits, authorization and authentication
security, request tracing, intrusion detection, and so on.
Implementers are further expected to have a solid understanding of the security implications of running a GraphQL service and are responsible for implementing relevant mitigations and solutions there. For example, they may: limit the size and token count of GraphQL documents; ensure document validity; limit the number of errors a response may return; limit information revealed via errors; enforce validation and execution timeouts and pagination limits; implement query depth and complexity limits; implement authentication and authorization; apply rate limits to critical logic; and so on.
Where this specification leaves flexibility for the implementer, the implementer should be very cautious when exercising this freedom. Implementers must make themselves aware of and account for the security implications of their choices; while many alternative choices can be secured, securing them is outside of the scope of this specification.
For example, this specification allows alternative media types to be used to
encode the request body; however, media types such as multipart/form-data or
application/x-www-form-urlencoded may result in the request being treated by a
browser as a "simple request", which does not require a "preflight", thereby
opening the server up to Cross-Site Request Forgery (CSRF/XSRF) attacks. The
recommended application/json media type requires a "preflight" check when
issued cross-domain. See
CORS protocol in the WHATWG
Fetch spec for more details on this.
Note: One approach used by the community to mitigate CSRF risks is to ensure a
request is not "simple" by requiring a custom header—such as
GraphQL-Require-Preflight—is included. The presence of a custom header forces
browsers to enact a "preflight" check, thereby adding an additional layer of
security. (This is not a standard header, and many alternative headers could
serve the same purpose. This is presented merely as an example of a pattern seen
in the community.)
Further extending this example, using multipart/form-data may allow large
values to be referenced multiple times in a GraphQL operation, potentially
causing the GraphQL service to process a much larger GraphQL request than the
HTTP request size would suggest.
For more detailed security considerations, please refer to RFC 7231, RFC 6454, other relevant RFCs, and other resources such as OWASP.
Supporting formats not described by this specification may have potential conflicts with future versions of this specification as ongoing development aims to standardize and ensure the security and interoperability of GraphQL over HTTP whilst accounting for its growing feature set. For this reason, it is recommended to adhere to the officially recognized formats outlined here.