Announcing the GraphQL over HTTP specification
Since the initial release of GraphQL in 2015, the GraphQL specification has always been transport agnostic.
Most of the GraphQL specification is about “services”, taking “requests” in, executing them, and producing “responses”. How those requests and responses are sent and received is up to the implementer.
This is generally useful. You can use GraphQL on your local machine, over raw TCP, avian carriers, or anywhere else. For the large crowd using GraphQL over HTTP, though, the lack of a specification made interoperability with other HTTP tools and observability more difficult than it should have been.
This is changing today with the first release of the GraphQL over HTTP specification!
The GraphQL specification stays transport agnostic; the GraphQL over HTTP specification is a new document, supplementary to the main GraphQL specification.
If you’re using GraphQL over HTTP, follow the guidance from the specification and ensure your servers, clients, proxies, and other services play well together.
Better observability
The GraphQL over HTTP specification includes a new application/graphql-response+json media type.
Previously, a lot of GraphQL servers were using application/json for their responses. This made it hard for clients to differentiate between a well-formed GraphQL response from the origin server and an error response from a proxy, cache, or other network intermediary.
As a workaround, most implementations set the status code to 200: if a client received a 200 status code, it knew the response wasn’t tampered with and was safe to parse as a GraphQL response.
This is not ideal from an observability point of view and led to some jokes about 200 Not OK. It’s hard to get the status of your service if everything is a 200…
This is now fixed!
When a client receives an application/graphql-response+json body, it knows it can parse it as a well-formed GraphQL over HTTP response, regardless of the status code.
The general rule is:
- If the request returned data, return a
2xxstatus code. - If the request returned only errors, return a
4xxor5xxstatus code.
The specification includes detailed guidance on which status codes should be used, but implementers may choose to use an alternative status code if it better fits the situation, so long as it is consistent with the general rule. Common status codes include:
- 405 when attempting a mutation over GET
- 406 when requesting an unsupported media type
- 415 when providing an unsupported media type
- 431 when headers are excessively large
- 500 when a server error occurs
A successful response would look like this:
HTTP/1.1 200 OK
Content-Type: application/graphql-response+json
...
{
"data": {
"hello": "world"
}
}A request error would look like this:
HTTP/1.1 422 Unprocessable Content
Content-Type: application/graphql-response+json
...
{
"errors": [{
"message": "Cannot query field 'foo' on type 'Query'."
}]
}The specification also introduces a new 294 Partial Success status code for use when both data and errors are present; you can read more about 294 Partial Success in the non-normative notes.
Documenting the fundamentals
“200 Not OK” issues aside, a lot of things have been working really well for GraphQL over HTTP over the past decade.
This specification documents all those things::
- URL
- GET requests
- POST requests
- JSON encoding
- Headers
- and more
It also includes non-normative notes about security, partial success, and future compatibility
What’s next?
This is just the beginning!
The IETF just moved the QUERY HTTP verb to a proposed standard.
QUERY is the perfect fit for GraphQL, and we already have plans to support it. We didn’t want to postpone this initial release or rush the implementation, but we hope to include it in the next revision of the GraphQL over HTTP specification.
Another thing that will benefit from standardization is Persisted documents. The technique of persisting GraphQL documents (“persisted queries”) has been in use since before GraphQL was open sourced in 2015, with different implementations solving different problems: performance, security, observability. We are eager to work with the community to build a standard approach that can solve all these issues whilst retaining future extensibility.
Finally, request batching will be a big win, particularly in the context of composite schemas (Federation) or when making requests to schemas you do not control.
Adopt it now!
If you are a GraphQL user, chances are you are already using the new specification without being aware of it! Most GraphQL frameworks and libraries out there already support the new specification.
If you are a library author, give the new specification a try!
In all cases, let us know what you think!