beginner·8 min read·Updated May 1, 2026

What is GraphQL? A Practical Introduction for Testers

GraphQL lets the client decide what data to fetch. Here's how it works and when it beats REST.

GraphQL in one sentence

GraphQL is a query language for APIs that lets clients ask for exactly the fields they need, in one request, instead of calling multiple REST endpoints and throwing away most of the response.

Created at Facebook in 2012, open-sourced in 2015, now used by GitHub, Shopify, Netflix, and many others. Not a replacement for REST — a different tool with different trade-offs.

The single-endpoint model

A REST API has many endpoints. A GraphQL API has one: typically POST /graphql. You send a query in the request body describing what you want, and the server returns exactly that shape.

{
  user(id: "abc-123") {
    name
    email
    posts(limit: 5) {
      title
      createdAt
    }
  }
}

Response:

{
  "data": {
    "user": {
      "name": "Alice",
      "email": "alice@example.com",
      "posts": [
        { "title": "Hello world", "createdAt": "2026-05-01T..." }
      ]
    }
  }
}

Note what you didn't do: you didn't call /users/abc-123 and then /users/abc-123/posts. One round-trip, exact fields, no over-fetching.

Try it

POST/graphql
A GraphQL query — ask for exactly these fields, get exactly those.
curl -X POST 'https://demo.totalshiftleft.ai/graphql' \
  -H 'Content-Type: application/json' \
  -d '{"query":"{ users(limit: 5) { items { id name email role } pageInfo { total } } }"}'

Change the query. Ask for fewer fields — the response shrinks. Ask for more — the server returns them. The client drives the shape.

Queries vs mutations

GraphQL has three operation types:

  • Query — read data. Like GET in REST.
  • Mutation — write data (create, update, delete). Like POST/PUT/PATCH/DELETE.
  • Subscription — long-lived connection for real-time updates. Like WebSockets.

Mutations look like queries but are prefixed with mutation:

POST/graphql
A GraphQL mutation — the GraphQL equivalent of a POST write.
curl -X POST 'https://demo.totalshiftleft.ai/graphql' \
  -H 'Content-Type: application/json' \
  -d '{"query":"mutation { createUser(input: { name: \"GraphQL Bob\", email: \"bob@graphql.com\" }) { id name email } }"}'

Mutations also return a shape you specify — you decide what fields of the created/updated resource come back.

The schema

A GraphQL API is defined by a schema: a strongly-typed description of every type, field, query, and mutation. Schemas are written in the GraphQL Schema Definition Language (SDL):

type User {
  id: ID!
  name: String!
  email: String!
  role: UserRole
  posts(limit: Int = 10): [Post!]!
}

type Query {
  users(limit: Int, sort: String): UserConnection!
  user(id: ID!): User
}

type Mutation {
  createUser(input: CreateUserInput!): User!
}

! means non-nullable. Types with ! after them are guaranteed present; types without can be null.

The schema is self-documenting. Tools can introspect any GraphQL endpoint and generate docs, SDKs, and tests automatically. Open /graphql in a browser on any GraphQL API — you usually get an interactive explorer called GraphiQL.

What GraphQL solves

  1. Over-fetching — REST returns full objects; GraphQL returns only requested fields.
  2. Under-fetching / N+1 requests — fetch user + posts + comments in one request instead of many.
  3. Versioning — instead of /v1/ and /v2/, you add fields (never breaking clients) and deprecate old ones with annotations.
  4. Typed client code — schemas enable auto-generated, type-safe SDKs in every language.

What GraphQL is bad at

  1. Caching — REST GETs cache trivially by URL. GraphQL everything-is-POST breaks HTTP caching; you need a dedicated cache layer (Apollo, Relay).
  2. File uploads — no standard way. Workarounds exist but are awkward.
  3. Error handling — returns 200 with errors in the body. Breaks tools that expect HTTP status codes to reflect success/failure.
  4. Learning curve — schema, resolvers, DataLoaders, fragments, directives — more concepts than REST.
  5. Performance ceiling — a poorly-written query can ask for everything and bring down the server.

What testers should know

Testing GraphQL is different enough from REST that it deserves its own lesson (see GraphQL testing guide). Headlines:

  • You still assert on HTTP 200 for a valid request — but check the errors array too.
  • Your test queries should be minimal — ask only for the fields you assert on, to keep tests fast and focused.
  • Mutations that fail validation often return 200 with errors; don't rely solely on HTTP status.
  • Schema changes can break clients silently; contract testing is essential.

When to use GraphQL

Good fit:

  • Mobile clients with bandwidth constraints (exact-field fetching saves a lot).
  • Dashboards that aggregate data from many sources into one view.
  • APIs with many client types (web, mobile, smart TV) — each picks the fields it needs.

Bad fit:

  • Simple CRUD APIs with one client. REST is easier.
  • File-heavy APIs (uploads, downloads).
  • APIs where HTTP caching is important (public content APIs, especially).

What's next

Now dig into queries vs mutations in depth, or compare all three protocols side-by-side in REST vs GraphQL vs SOAP.

Related lessons

Read more on the blog