GraphQL API testing checks an API where the client asks for exactly the fields it wants in a single query, sent to one endpoint. The ideas you know from REST testing still apply, but three things change how you test: everything goes through one URL, errors usually come back with HTTP 200, and the client controls the shape of the response. This guide covers what to test and how, with Postman and REST Assured examples.
GraphQL vs REST in One Minute
| REST | GraphQL | |
|---|---|---|
| Endpoints | Many: /users, /users/7/orders | Usually one: /graphql |
| Who decides the response fields | The server | The client, field by field |
| Reading data | GET | A query, usually sent with POST |
| Changing data | POST / PUT / PATCH / DELETE | A mutation |
| Errors | HTTP status codes (400, 404, 500) | Often HTTP 200 with an errors array |
| Contract | OpenAPI spec (optional) | A typed schema (always present) |
Anatomy of a GraphQL Request
A GraphQL request is an HTTP POST with a JSON body containing the query text and, ideally, separate variables:
POST /graphql HTTP/1.1
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...
{
"query": "query GetUser($id: ID!) { user(id: $id) { id name email orders(first: 2) { id total } } }",
"variables": { "id": "7" }
}
The response mirrors the query, with only the requested fields:
{
"data": {
"user": {
"id": "7",
"name": "Asha",
"email": "asha@example.com",
"orders": [ { "id": "1042", "total": 499 }, { "id": "1043", "total": 1299 } ]
}
}
}
A mutation looks the same but starts with mutation, for example mutation { createUser(input: {name: "Ravi"}) { id } }.
What to Test in a GraphQL API
1. The schema
The schema is the contract. Check that types, required fields (marked !) and enum values match the requirements, and watch for breaking changes between releases: a removed field or a field that became required breaks existing clients. Tools such as GraphQL Inspector can compare two schema versions automatically.
2. Queries and field selection
- Ask for one field, many fields and nested objects; the response must contain exactly what was asked, no more.
- Check nullable fields return
null(not an error) when data is missing. - Test arguments: valid IDs, unknown IDs, filters, sorting and pagination (
first/aftercursors orlimit/offset).
3. Mutations
Verify the change actually happened (query it back or check the database), that the mutation returns the updated object, and that invalid input is rejected with a clear message. Test that running the same mutation twice behaves as designed, for example no duplicate orders.
4. Errors and the 200 trap
This is where most REST habits fail. A GraphQL server usually returns HTTP 200 even when the query fails, with details in an errors array:
{
"data": { "user": null },
"errors": [ { "message": "User not found", "path": ["user"], "extensions": { "code": "NOT_FOUND" } } ]
}
So never assert only on the status code. Check that errors is absent for valid requests, and for invalid ones assert on the error code and message. Also note that a response can be partly successful: some fields in data and an error for another field.
5. Authorization at field level
Because one query can reach many objects, check permissions on every type and field, not just the endpoint. A normal user querying another user's orders or an admin-only field like salary must get an error or null, never the data.
6. Abuse and performance
- Deeply nested queries (user → orders → user → orders …) can overload the server; there should be a depth or complexity limit.
- Large page sizes such as
first: 100000should be capped. - N+1 queries: a list of 50 users with their orders shouldn't trigger 51 database calls; watch response time as the list grows.
- Introspection is useful in test environments but is often disabled in production; check what your team decided.
Testing GraphQL in Postman
In a Postman request, set the method to POST, choose Body → GraphQL, and write the query and variables in the two panels. Postman can fetch the schema for autocompletion. Tests are written the same way as for REST:
const body = pm.response.json();
pm.test("no GraphQL errors", () => pm.expect(body.errors).to.be.undefined);
pm.test("returns the requested user", () => {
pm.expect(body.data.user.id).to.eql("7");
pm.expect(body.data.user).to.have.all.keys("id", "name", "email", "orders");
});
Testing GraphQL with REST Assured
REST Assured has no special GraphQL support and doesn't need it: send the query and variables as a JSON body.
String query = "query GetUser($id: ID!) { user(id: $id) { id name email } }";
Map<String, Object> payload = Map.of("query", query, "variables", Map.of("id", "7"));
given()
.baseUri("https://api.example.com")
.contentType(ContentType.JSON)
.auth().oauth2(token)
.body(payload)
.when()
.post("/graphql")
.then()
.statusCode(200)
.body("errors", nullValue())
.body("data.user.id", equalTo("7"))
.body("data.user.email", containsString("@"));
Keep queries in .graphql files under src/test/resources and load them in tests, so they are readable and reusable.
GraphQL Testing Checklist
| Area | Check |
|---|---|
| Schema | Types, required fields and enums match; no unplanned breaking changes |
| Queries | Exact field selection, nested objects, nulls, arguments, pagination |
| Mutations | Data really changes, invalid input rejected, repeat calls handled |
| Errors | errors array checked, not just HTTP 200; partial results handled |
| Security | Field-level authorization, depth/complexity limits, page-size caps |
| Performance | Response time with large lists, no N+1 behaviour |
FAQs
Is GraphQL testing different from REST API testing?
The goals are the same, but GraphQL uses one endpoint, lets the client pick fields, and usually returns HTTP 200 even for errors. Tests must check the errors array, field selection and field-level permissions.
Can Postman test GraphQL APIs?
Yes. Choose Body → GraphQL in a POST request to write queries and variables, fetch the schema for autocompletion, and write tests in the Tests tab as usual.
Why does a failed GraphQL request return status 200?
Because the HTTP request itself succeeded; the failure is reported in the errors array of the JSON response. Some servers do return 4xx for malformed requests, but you should always assert on errors.
What is introspection in GraphQL?
A built-in query that returns the API's schema: its types, fields and arguments. Tools use it for autocompletion and documentation; many teams disable it in production.