skip to content

What are the top-level keys of a GraphQL response body, and which of them may be absent?

level: juniorimportance: must knowfreq 72%

answer

  1. Count the keys the spec allows
  2. One of the three is a closed door
  3. Absent is not the same as empty
  4. Both keys at once is normal
  5. data, errors, extensions and nothing else

basics

~20 s

Three, and no others: data, errors and extensions. The errors key appears only when something went wrong, and is then never empty. The data key is absent when the operation never executed. The extensions key is optional and free-form.

solid answer

~50 s

A GraphQL response is a single map with at most three entries. `data` carries the execution result; it is present whenever execution happened, and absent when the request failed before execution began. `errors` is present **if and only if** at least one error was raised, and its value is then a non-empty list — a conformant server never sends `"errors": []`. `extensions` is optional, must be a map when present, and is reserved for the implementor with no restrictions on what goes in it. The rule people forget is the closing one: the top-level map **must not carry any other entry**, so a server that adds its own `meta` or `requestId` beside `data` is emitting a non-conformant response. `data` and `errors` are not mutually exclusive — a response holding both is the normal shape when a field failed mid-execution.

code

json · 9 lines
json
{
  "data": {
    "release": {
      "title": "Nightshift Sessions",
      "trackCount": 11,
      "label": { "name": "Cold Harbor Records" }
    }
  }
}

go deeper

for a junior

Be ready to name all three keys — data, errors, extensions — and to say that errors is simply absent when nothing failed. Interviewers ask this to check you have looked at a raw response body rather than only at what a client library handed you.

for a middle

Explain the mechanics precisely: errors present if and only if something failed and then never empty, data absent when the request never executed, extensions optional and a map. Be able to state that the top-level map is closed to any other entry and say why that closure exists.

for a senior

Show the operational instinct: never write a client that discards data because errors is present, never parse positionally, and never let a server bolt an extra top-level key on for convenience. Be able to describe the partial-response shape from memory.

for a principal

Own the contract angle. When several teams build clients against one graph, the envelope rules are the only thing every client can rely on, so the tradeoff is whether shared per-response metadata is worth the coupling of a house extensions convention versus keeping clients portable.

## One map, three keys, nothing else The GraphQL specification defines a response as a **map** — an unordered set of key/value entries — which in practice is serialized as a JSON object. It is unusually strict about what that map may hold. Exactly three entries are defined: `data`, `errors` and `extensions`. And the rule that catches candidates out is the closing one: the top-level response map **must not contain any entry other than those three**. A server that helpfully adds `meta`, `status`, `requestId` or `traceId` alongside `data` is emitting a non-conformant response, however useful the extra key is downstream. That closure is not fussiness for its own sake. It is the mechanism that lets the protocol grow. Because no conformant server puts arbitrary keys at the top level, a future edition of the specification can define a new top-level entry without colliding with something a vendor already shipped. Everything a server wants to add goes into one designated slot instead of into the open namespace. ## `data` `data` is the result of executing the operation. Its presence answers a single question: *did execution happen at all?* * If the operation was executed, `data` is present. Its value is the result map, or the JSON value `null` if execution produced no usable result. * If the operation failed **before** execution — the document did not parse, did not validate, or a variable could not be coerced — `data` is not present at all. Not `null`; simply not a key in the map. The difference between "absent" and "present with the value null" is a genuine distinction in the envelope, and it is the one clients most often flatten by accident. ## `errors` `errors` is present **if and only if** the operation raised at least one error. Both halves of that biconditional are load-bearing. If nothing went wrong, `errors` must not be present. Not present-and-empty, not present-and-null — absent. If something did go wrong, `errors` is present and its value is a **non-empty list** of error maps. There is no conformant response containing `"errors": []`. The practical consequence is the shape of the client-side check. Testing `body.errors && body.errors.length > 0` is defensive code written by someone who does not trust the contract; the contract says presence alone is the signal. A length check does no harm, but a client that concludes "nothing failed" because the list came back empty is coding against a response no conformant server produces — and is more likely to be papering over its own deserialization bug. ## The two are not mutually exclusive The single most common misconception is that a response is *either* a data response *or* an error response, the way many hand-rolled HTTP APIs are shaped. GraphQL is not. When a field fails partway through execution, the server keeps the parts of the result it did produce and reports the failure beside them. Both keys are present, and the response is completely normal: ```json { "errors": [ { "message": "Play counts are temporarily unavailable" } ], "data": { "release": { "title": "Nightshift Sessions", "trackCount": 11, "label": { "name": "Cold Harbor Records" } } } } ``` A client that throws away `data` the moment it sees an `errors` key discards a correct, usable result — and it will do that on every partial failure, not just on catastrophic ones. ## `extensions` `extensions` is optional. If it is present its value must be a map, and the specification places **no restrictions whatsoever** on what that map contains: it is reserved for implementors to extend the protocol as they see fit. It may appear on a successful response, on a failed one, or on neither. ## Key order The specification notes that serializing `errors` before `data` is helpful when reading a response by eye during debugging. That is a serialization suggestion, not a semantic rule — JSON object keys are unordered, and no client should ever parse positionally or infer anything from where a key landed in the bytes. ## What this looks like on the wire A clean success carries one key: ```json { "data": { "release": { "title": "Nightshift Sessions", "trackCount": 11 } } } ``` A request that never executed carries one key too, but a different one: ```json { "errors": [ { "message": "Cannot query field 'trackCont' on type 'Release'." } ] } ``` Note there is no `data` key in that second body at all. ## Why interviewers ask it It is a five-second question with a long tail. The candidate who answers "data and errors" and stops has usually only ever read `response.data` out of a client library and has never looked at a raw body. The candidate who says "three keys, nothing else may be added, `errors` is absent or non-empty, and both keys together is the normal partial-failure shape" has debugged a real GraphQL response and is ready for every follow-up in this area.

  • May a GraphQL response contain an errors key whose value is an empty list?
    No. The specification says the entry is present only when at least one error was raised, and that its value is then a non-empty list. An empty list is a non-conformant response. The client-side consequence is that presence of the key is the signal — a length test is redundant, and a client that reports success because the list was empty is trusting a body no conformant server sends.
  • Does the order of the keys in a GraphQL response body carry any meaning?
    No. The response is a map and JSON object keys are unordered. The specification does suggest serializing `errors` before `data` so a human reading a body during debugging sees the failure first, but that is a formatting courtesy. Nothing may be inferred from position, and a client that parses positionally rather than by key is broken.
  • A response carries a fully populated data map and a non-empty errors list. Is it malformed?
    No, that is the ordinary shape when an error was raised during execution rather than before it. The server completed the parts of the result it could and reported the failure alongside them. Both entries belong in the same body, and treating the presence of `errors` as grounds for discarding `data` throws away a usable response.

The envelope is a form with exactly three printed boxes. You may leave boxes blank, but you may not staple an extra sheet to the front.

saying these in an interview costs you the question

  • Says errors is always present, sometimes empty
  • Thinks a server may add its own top-level key
  • Believes data and errors are mutually exclusive
  • Assumes an absent data key means the same as null
  • Treats extensions as required on every response
  • Infers meaning from the order of the keys

context