GraphQL API Testing
GraphQL is replacing REST in NZ SaaS startups and scale-ups. Unlike REST, a single endpoint handles everything — which means traditional API testing approaches break down. This page teaches you to think in queries, mutations, and subscriptions.
1 The Hook
An Auckland FinTech migrates their public API from REST to GraphQL. The QA team keeps their existing Postman collection, just changing the URL. Tests pass. Go-live. Three weeks later a client reports they can retrieve other customers' account balances by crafting a specific nested query.
The QA team never tested deeply nested queries or field-level authorisation — because that's not how REST testing works. Each REST endpoint had a fixed shape and a fixed set of fields. In GraphQL, the client decides what fields to request. A field that is technically in the schema but should be restricted by role is now exposed to anyone who knows to ask for it.
The breach cost the FinTech a Privacy Act notification, a regulator conversation, and six months of trust-rebuilding. The fix was two lines of authorisation code in the resolver. The test gap was the entire GraphQL mindset.
2 The Rule
"In GraphQL there is one endpoint but infinite queries. You cannot test a list of URLs — you must test the schema, the resolvers, and the authorisation logic on every field."
A 200 OK response means nothing on its own in GraphQL. Errors appear inside the response body, not in HTTP status codes. A query that returns forbidden data still returns HTTP 200. Your assertions must inspect the payload, not just the status line.
3 The Analogy
REST is a fixed menu. GraphQL is a buffet.
At a restaurant with a fixed menu, you order dish 12, you get dish 12 — nothing more, nothing less. Testing is straightforward: does dish 12 arrive correctly? GraphQL is a buffet where customers build their own plate from every available dish. You have to test not just the individual dishes, but every possible combination — including whether customers can reach into the staff-only kitchen and grab food they are not supposed to have.
4 Watch Me Do It
Scenario: a NZ property listing API exposes a property query. Let's work through a full test session in Insomnia or Postman's GraphQL mode.
Step 1 — Discover the schema with introspection
Before writing a single test, run an introspection query. This tells you every type, field, and argument the API exposes. In Insomnia, select GraphQL body type and hit the schema refresh button. In Postman, use the GraphQL tab.
This reveals every field in the schema, including ones the UI never renders. That's your attack surface.
Step 2 — Test field-level authorisation
The property query has an owner sub-field. Some owner fields are legitimate (name), others are sensitive (email, bank account). Test each as an unauthenticated user and as a buyer role.
Expected: unauthenticated request returns null or an error for email and bankAccount, not the actual values.
Step 3 — Test with invalid types
Pass a string where an ID is expected, a negative integer for bedrooms, and an empty string for a required field. GraphQL has a type system — the server should reject malformed inputs with a descriptive error, not a 500.
Step 4 — Test query depth limits (DoS protection)
GraphQL allows arbitrary nesting. Without a depth limit, a malicious client can craft a query that forces the server to resolve millions of objects.
Send this query and observe the response. A protected API returns an error like "Query depth limit of 5 exceeded". An unprotected API either times out, returns an error from the database layer, or — worst case — succeeds and pegs CPU.
Step 5 — Test mutations
Mutations are the GraphQL equivalent of POST/PUT/DELETE. Test create, update, and delete with: valid inputs (happy path), missing required fields, duplicate data (if uniqueness is enforced), and cross-user mutation (can user A delete user B's listing?).
5 When to Use It
Any application that exposes a GraphQL endpoint needs this testing approach. Key scenarios:
- Schema validation — does the schema match the API contract agreed with consumers?
- Field-level authorisation — does every sensitive field enforce role checks at the resolver, not just the UI?
- Query depth and complexity limits — is the API protected against denial-of-service via deeply nested or expensive queries?
- Pagination testing — cursor-based pagination is common in GraphQL; test first/last/before/after edge cases
- Subscription testing — real-time WebSocket subscriptions need connection lifecycle, message ordering, and authorisation tests
- Error handling — partial success (some fields resolve, others error) is a unique GraphQL pattern that needs explicit test coverage
- Introspection control — verify introspection is disabled in production environments
6 Common Mistakes
🚫 Testing GraphQL like REST
I used to think: I can test GraphQL the same way as REST, just with a different URL.
Actually: GraphQL has no HTTP verbs, no resource paths, and no standard error codes. A 200 response can still contain errors in the response body. Your test assertions must inspect response.data and response.errors, not just the HTTP status.
🚫 Assuming happy-path means secure
I used to think: If the happy path query works, the API is secure.
Actually: GraphQL's flexibility means malicious users can craft queries that expose fields they should never see, or nest queries deep enough to cause a denial of service. Security testing in GraphQL requires deliberately adversarial queries — not just the ones the front-end was designed to send.
🚫 Leaving introspection on in production
I used to think: Introspection is a useful testing tool in all environments.
Actually: Introspection should be disabled in production — it hands attackers a complete map of your schema, including fields that are visible but insufficiently protected. Test that introspection returns an error in production as an explicit security check in your test suite.
7 Now You Try
Use the prompt lab below. Write your prompt, then run it to get feedback from a real AI.
A NZ e-commerce GraphQL API has a product query that returns product details including a seller field with sub-fields: name, email, payoutAccount, and taxNumber. Write 5 test cases covering: happy path (authenticated buyer), unauthenticated access, field-level authorisation for sensitive seller fields, an introspection check, and a query depth limit test.
8 Self-Check
Click each question to reveal the answer.
What HTTP status code does a GraphQL error typically return, and why is this different from REST?
GraphQL typically returns HTTP 200 even when the query contains errors. The actual errors appear in a top-level errors array in the JSON response body. REST uses HTTP status codes (400, 404, 500) to signal error categories. In GraphQL you must always inspect the response body — a green HTTP status means nothing on its own.
What is an introspection query and why should it be disabled in production?
An introspection query uses the reserved __schema or __type fields to retrieve the complete schema definition from a GraphQL API — every type, field, argument, and relationship. It is invaluable for development and testing. In production it should be disabled because it gives attackers a detailed map of your entire data model, making it far easier to discover sensitive fields and craft targeted exploits.
Describe a GraphQL-specific denial of service attack and how to test that it's prevented.
A query depth attack exploits GraphQL's nesting capability by sending a deeply nested query (e.g., user { friends { friends { friends { ... } } } }). Each level multiplies the number of database calls, potentially causing the server to time out or exhaust resources. To test prevention: send a query that exceeds the expected depth limit and assert the response contains a depth-limit error (not a timeout or 500). Also test query complexity limits — a query with many sibling fields can be equally expensive even if it is not deeply nested.
9 ISTQB Mapping
CTAL-TA v3.1.2 — Section 3.2.4: Testing web services
The CTAL-TA syllabus covers testing web services delivered over HTTP, which includes GraphQL as a query language operating over standard HTTP. Competencies include interface testing, contract validation, and boundary value analysis applied to API inputs.
CTAL-TAsec — Security testing competencies
Field-level authorisation failures and introspection exposure map directly to OWASP API Security Top 10 items (Broken Object Level Authorisation, Excessive Data Exposure). The CTAL-TAsec syllabus requires testers to identify and validate controls for both categories.
10 Next Steps
GraphQL sits at the intersection of API testing and security testing. These pages extend what you've learned here: