GraphQL over HTTP and clients

GraphQL · Practical · 12 min

Every GraphQL client, from fetch to Apollo, speaks this simple HTTP protocol.

GraphQL over HTTP is standardized by the GraphQL foundation's GraphQL-over-HTTP specification. A request is normally a POST with a JSON body:

{"query": "...", "operationName": "Book", "variables": {"id": "b1"}}

Send Content-Type: application/json and Accept: application/graphql-response+json, application/json. Queries (never mutations) may also be sent as GET with URL-encoded query and variables parameters, which makes them cacheable by CDNs.

Status codes: servers using the newer application/graphql-response+json media type return 4xx for requests that fail before execution (parse or validation errors), and 200 when execution started, even if some fields errored. With classic application/json, 200 is used for nearly everything, so clients must always inspect the errors array.

A plain fetch is enough for scripts. Client libraries add a lot:

  • Normalized caching by __typename + id (Apollo Client, urql's graphcache, Relay).
  • Code generation of TypeScript types from the schema and operations (GraphQL Code Generator).
  • Fragment colocation, pagination helpers, retries, subscriptions.

Servers commonly expose GraphiQL or a similar IDE at the endpoint in development; turn it (and introspection for public APIs) off or restrict it in production if your schema is private.

Example

const res = await fetch("https://countries.trevorblades.com/graphql", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Accept: "application/graphql-response+json, application/json",
  },
  body: JSON.stringify({
    query: `query Country($code: ID!) { country(code: $code) { name capital } }`,
    operationName: "Country",
    variables: { code: "AM" },
  }),
});
const { data, errors } = await res.json();
if (errors) console.error(errors);
console.log(data.country); // { name: 'Armenia', capital: 'Yerevan' }

Remember

  • POST JSON with query, operationName and variables
  • GET is allowed for queries and enables HTTP caching
  • Always check errors, even on HTTP 200

Watch out for

  • Sending mutations over GET; servers must reject them to avoid CSRF-style side effects.

Check yourself

  1. Which operations may be sent with HTTP GET?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: graphql.org/learn/serving-over-http/