skip to content

Does the GraphQL specification define how a request travels over HTTP?

level: middleimportance: nice to knowfreq 27%

answer

  1. Two documents, not one
  2. The core specification never says HTTP
  3. Even the serialization is only recommended
  4. The serving rules came later, and are still a draft
  5. Convention converged before anything was specified

basics

~20 s

No. The GraphQL specification is transport-agnostic: it defines the language, the type system and the execution algorithm, and stops at a result. HTTP serving is described by a separate document, GraphQL over HTTP, still a working draft.

solid answer

~40 s

The core specification describes a request abstractly — a document, variable values, an optional operation name — and a response as a map with `data`, `errors` and `extensions` entries. It recommends JSON as a serialization without requiring it, and it names no transport at all. For years the HTTP conventions everybody uses — a JSON POST carrying `query`, `variables`, `operationName` and `extensions` to a single URL, and a GET carrying the same as URL parameters — were de facto practice copied between implementations rather than anything written down. The GraphQL over HTTP specification, a separate working draft, records those conventions. The practical consequence is that "the spec says" is ambiguous whenever the subject is HTTP-shaped: name which document you mean, and expect servers to diverge on the details the draft is still settling.

go deeper

for a junior

Remember the headline: GraphQL is a query language and an execution model, not a transport. HTTP is how it usually travels, and that carriage is written down in a different document.

for a middle

Be able to draw the line precisely — language, type system, validation, execution and result shape on one side; parameters, methods, media types and status codes on the other — and note that serialization is recommended, not required.

for a senior

Use the distinction operationally: expect divergence between servers on anything the draft has not settled, and never plan a client on behaviour that is convention rather than specification without pinning it in your own contract and tests.

for a principal

Own where your organisation stands relative to an in-progress standard: what you depend on today, what would break if a draft requirement tightened, and how much of your HTTP behaviour is written into your own contract rather than borrowed.

## Two documents, two jobs It helps to see GraphQL as layered. The GraphQL specification defines a language (the syntax of documents and schema definitions), a type system, a validation phase, an execution algorithm, and the shape of a result. That is the whole of it. It says nothing about URLs, methods, headers, status codes or connections, and this is deliberate: the specification talks about *executing a request against a schema*, not about receiving one. Even serialization is left open. The specification discusses how its concepts — maps, lists, null, strings, numbers — should map onto a serialization format and recommends JSON, but does not mandate it. A perfectly conformant implementation could serialize results in a binary format, and some do internally. The serving layer is the second document. The GraphQL over HTTP specification, a working draft rather than a released edition, describes how to express a request as an HTTP request and a result as an HTTP response: the request parameters, the query-string form, the restriction of GET to query operations, the media types and status codes. ## Why this order of events matters GraphQL was released with a reference implementation whose HTTP handling everyone copied. Convergence was social rather than normative: clients were written against the behaviour the first widely used servers happened to have, new servers matched them so those clients would work, and within a couple of years "POST a JSON body with a `query` key to `/graphql`" was universal without being specified anywhere. That history explains the residue. The parts everyone copied early are extremely consistent across implementations. The parts nobody had to agree on — whether GET is supported at all, which status code accompanies a document that failed validation, how strictly the request content type is checked — are where servers still differ, and they are precisely what the working draft is pinning down. ## Why transport-agnosticism is not a technicality It is what allows the same schema and the same execution engine to serve operations that never touch HTTP: - Executing a document in-process against a schema, with no network at all — used for server-side rendering, for tests, and for embedding a graph inside an application. - Subscriptions, which need a long-lived stream and are carried by a WebSocket subprotocol or by a server-sent event stream rather than by a request-response exchange. - Message-based transports inside a system, where an operation arrives on a queue. In every case the execution algorithm is identical; only the envelope changes. If HTTP had been baked into the core specification, each of those would have needed its own dialect. ## What it means to say a document is a working draft A working draft is an in-progress standard: it can gain requirements, tighten wording and reclassify a SHOULD as a MUST between readings. Three habits follow. Quote it as a draft, not as settled law. Do not assume a server you did not write implements the parts you rely on, especially around GET support and status codes. And when you depend on behaviour that appears in neither document, recognise it as a convention your servers happen to share, and write it into your own contract explicitly rather than assuming it travels. ## The interview version of this answer The question is usually phrased casually — "is GraphQL an alternative to REST over HTTP?" — and the difference between a fluent answer and a memorised one is exactly this layering. GraphQL is a query language and an execution model; HTTP is one carriage for it, the dominant one, described by a companion draft. Being able to say which document owns which rule is also the habit that keeps you from attributing a widespread convention to the specification, which is the single most common way GraphQL claims turn out to be wrong. A candidate who adds one concrete example — a subscription that leaves HTTP behind for a stream, or a document executed in-process in a test with no server involved — has demonstrated the point rather than recited it.

  • Name a way GraphQL is executed with no HTTP involved at all.
    Executing a document in-process against a schema — common in tests and in server-side rendering, where the code calls the execution engine directly. Subscriptions are another: they need a stream, so they ride a WebSocket subprotocol or a server-sent event stream. The document, validation and execution are identical in every case; only the envelope differs.
  • If the HTTP rules were unwritten for years, why did implementations agree?
    Because clients were built against the behaviour of the earliest widely used servers, and any new server that wanted those clients to work had to match it. The agreement was social, not normative, which is why the well-copied parts are uniform while the parts nobody was forced to agree on — GET support, status codes, content-type strictness — still vary.
  • How do you check whether an HTTP behaviour you rely on is actually normative?
    Look for it in the right document: language, type system, validation and execution in the GraphQL specification; request and response carriage in the GraphQL over HTTP draft. If it is in neither, it is a convention your servers happen to share. That is not a reason to abandon it, but it is a reason to write it into your own contract and test it rather than assume portability.

The core specification is the rules of a card game; GraphQL over HTTP is the etiquette for playing it by post. You can play at a table, over the phone or by post, and the rules of the game never change.

saying these in an interview costs you the question

  • Calls GraphQL an HTTP protocol
  • Says the GraphQL specification mandates POST and JSON
  • Treats GraphQL over HTTP as a released edition
  • Assumes every server behaves identically over HTTP
  • Thinks a result must be JSON by specification

context