Why does a failed GraphQL call come back 200 OK?
A GraphQL response is a JSON object. Its data entry holds the result and its errors entry holds what went wrong [1]. A field that fails is replaced with null while the rest of the result still arrives, so one response can hold both [1].
HTTP has no status code for "partly worked". The GraphQL project's guidance is that a response with a data entry that is not null gets a 2xx status, even when it also has errors [2]. The GraphQL-over-HTTP draft says the same, and calls a 4xx or 5xx "not appropriate" for a partial result [3].
When a request fails before it runs, because of a syntax or validation error, the response has no data entry. Servers usually answer 400 then, but the GraphQL project notes that some older servers answer 2xx when the response type is application/json [2]. Some APIs use 200 for every error in the application itself: monday.com's API documentation says it answers 200 OK for those and keeps other statuses for problems in transport [4].
So the status is not enough. Read the body.
What does a GraphQL error look like?
An example: the user was found, but one field of it failed.
{
"data": { "user": { "name": "Ada", "photo": null } },
"errors": [
{ "message": "Photo unavailable.", "path": ["user", "photo"] }
]
}
Every error has a message. It may also have locations (the line and column in your query), a path (which field failed) and extensions (extra detail the API adds) [1]. Three shapes are common:
- Partial result: most fields arrived, the failed ones are null, and
pathsays which. A page built from this may look half empty. - No result:
datais null, because an error stopped the whole result [1]. - No data entry at all: the request never ran, for example a syntax error in the query [1].
How do I spot it in the browser by hand?
- Open the DevTools Network panel and choose the Fetch/XHR filter [5].
- Click the GraphQL call. A GraphQL API is typically one address ending in
/graphql[2], so the address does not say which operation it was: read the request to find out. - Open its response and look for
errors. The status column will still say 200.
This works for one call you are already looking at. It does not warn you about the one you did not open.
How does RequestFox catch it for me?
Record the calls
Press Start in RequestFox and use your app. How to record API calls.
Look for the GraphQL error mark
A call whose answer holds an
errorslist is marked "GraphQL error", and it is listed among the session's findings in the Overview. A 4xx or 5xx answer is already marked Failed by its status.Open the call
The card shows the first error's message and, when there are more, how many. Open it to read the whole answer.
Press "Why is this flagged?"
The finding code is
RF-GQL-ERROR. The panel explains it offline, andrequestfox-ci explain RF-GQL-ERRORsays the same in a terminal.
What RequestFox looks for, so you know what it will and will not flag:
- The answer is JSON with an
errorslist in which every error is an object with a textmessage. - The call looks like GraphQL: its address contains "graphql", or a
?query=holds an operation, or the request body has aquerythat reads like a GraphQL document or a persisted-query id. A REST API that lists "errors" for its own reasons is not marked as GraphQL. - A batch (a list of answers) counts if any one of them failed.
- An answer cut off at the capture limit is not read.
A server that reports failure some other way, such as a field named error or a status inside data, is not caught by this rule. Add a check on that field to the endpoint instead: checks can test fields, status, time and headers.
How do I make a CI run fail on it?
The command-line tool, requestfox-ci, makes the same check. In assert, a step whose answer carries GraphQL errors fails with "no GraphQL error". For a suite that tests error paths on purpose, put "bodyErrors": false in its config to switch the check off. How to run API checks in CI.
How do I test how my app handles a GraphQL error?
Make the API return one. Record the real call, open its card, choose ··· More → Mock this response, then change the rule's body in Settings → Mocks, rules & checks to an answer with an errors list, with status 200. Reload the page: it gets your answer, and the card says MOCKED so nobody files it as a bug. How to mock an API response.
Sources
- GraphQL specification, October 2021, section 7 "Response". Checked . spec.graphql.org
- GraphQL.org, "Serving over HTTP", Status Codes. Checked . graphql.org
- GraphQL over HTTP, current working draft, section 5.4 "Status Codes". A draft, not a final standard. Checked . http-spec.graphql.org
- monday.com developer documentation, "Error handling". Checked . developer.monday.com
- Chrome for Developers, "Network features reference". Checked . developer.chrome.com
Something here out of date? Specs and APIs change. Tell us at the address in the privacy policy and we will fix it.
Next
- Mock an API response
Return your own answer, or make a call fail.
- Run API checks in CI
A suite, a config file and one command.
- Record API calls
Start, use the site, read the flags, keep the evidence.
- Duplicate and N+1 API calls
Find calls sent twice, and one request per id in a list.