Errors
GraphQL errors arrive with HTTP 200
This is the single most important thing to get right. A GraphQL request that
fails still returns HTTP 200, with the failure described in an errors
array:
If your HTTP client checks only the status code, every one of these looks like a success.
Most GraphQL client libraries do this for you. Hand-rolled fetch calls are
where this bites.
Partial success is possible
errors and data are not mutually exclusive. A query requesting several
fields can return data for some and an error for others — the failed field is
null in data, and path in the error names it. Do not assume errors being
present means data is unusable.
Error fields
| Field | Meaning |
|---|---|
message | Human-readable description |
path | Which field in your query failed |
locations | Line and column in your query document |
OAuth errors are different
The token and revoke endpoints are REST and use real status codes:
| Situation | Status | Body |
|---|---|---|
Missing Authorization header | 401 | authorization error — plain text |
Bad client ID or secret | 401 | {"error":"invalid_client","error_description":"..."} |
Unsupported grant type | 403 | {"error":"unsupported_grant_type",...} |
Two things to code around: the missing-header response is not JSON, so parsing
it will throw; and unsupported_grant_type returns 403 where RFC 6749 §5.2
specifies 400.
Always capturex-request-id
Every response carries a request ID:
Log it alongside failures. It is the correlation key support will ask for, and it is the difference between a diagnosable report and "the API returned an error yesterday".
Retrying
Retry with exponential backoff on 429 (see Rate limits)
and on 5xx.
Do not blindly retry GraphQL errors returned with HTTP 200 — most are deterministic (bad scope, missing permission, invalid ID) and will fail identically forever.
Mutations are not idempotent and there is no idempotency-key mechanism. Retrying
a mutation that may have succeeded can duplicate its effect. Before retrying,
query to establish current state — for example, re-read the order before
re-sending acceptOrder.