Q11 of 20 · GraphQL

Why is asserting on HTTP 200 not enough for a GraphQL test?

GraphQLJuniorgraphqlerror-handlingfundamentalsapi

Short answer

Short answer: GraphQL returns 200 OK for most logical errors — the failure is in the response body's `errors` array, not the status line. A test that only checks `status === 200` will pass a response where the operation actually failed.

Detail

This deserves its own question because it's the most common GraphQL testing mistake.

In REST, 404 or 400 tells you something went wrong. In GraphQL over HTTP, the transport succeeded — the server received and processed the query — so it returns 200. Whether the operation succeeded is reported in the body:

// HTTP 200 OK — but this is a FAILURE
{ "data": null, "errors": [{ "message": "Field 'foo' doesn't exist", "extensions": { "code": "GRAPHQL_VALIDATION_FAILED" } }] }

A test like expect(response.status).toBe(200) passes this broken response.

The correct pattern:

  1. Status 200 confirms the transport worked (still worth a sanity check).
  2. The real assertions are on the body: expect(body.errors).toBeUndefined() for success, or expect(body.errors[0].extensions.code).toBe("EXPECTED_CODE") for a negative case.

(Note: some servers do return non-200 for transport-level issues like malformed JSON or auth failures, so status isn't useless — it's just not sufficient.)

// WHAT INTERVIEWERS LOOK FOR

Clear statement that 200 means transport-OK not operation-OK, and that body assertions are the real check.

// COMMON PITFALL

Building an entire suite on status assertions and discovering in prod that failures were passing all along.