API Styles Deep Dive · 2 of 7

GraphQL — Ask for Exactly What You Need

GraphQL is a query language for APIs. The client sends a query describing the exact shape of data it wants; the server returns that shape, no more, no less. One endpoint, a strongly typed schema, deeply nested data in a single round-trip — and a fresh set of problems to manage.

Query LanguageSchema-FirstOne EndpointApollo
← Back to APIs & Networking
Quick Facts

What GraphQL Is

Basic Concepts

  • Origin: built at Facebook (2012), open-sourced 2015. Born from the pain of mobile clients chaining REST calls to render one screen.
  • One endpoint: almost always POST /graphql. The body is the query.
  • Strongly-typed schema: the server publishes a typed contract. Clients introspect it; tools generate type-safe code.
  • Three operation types: query (read), mutation (write), subscription (live updates, usually over WebSocket).
  • Resolvers: functions on the server that fetch each field. The schema describes the shape; resolvers do the work.
  • Tooling stars: Apollo (server & client), GraphiQL (in-browser query explorer), Hasura, Relay, urql, codegen.
Why It Wins

What You Buy

No Over- or Under-fetching

The mobile screen needs user.name, the user's last 3 orders, and each order's total. In REST: 1 + 1 + 3 round-trips, plus a lot of fields you didn't want. In GraphQL: one round-trip, exactly those fields.

query {
  user(id: 42) {
    name
    orders(last: 3) {
      total
    }
  }
}
One Schema, Many Clients

A typed contract that web, iOS, and Android can all share. Each client asks only for the fields it needs from the same backend. Removes the temptation to ship one BFF endpoint per screen.

Aggregating Many Backends

The GraphQL server can call several REST APIs, a couple of databases, and a search engine, then return one consolidated tree. The client doesn't see the orchestration — and the orchestration logic stays in one place rather than smeared across mobile and web codebases.

Excellent Developer Tooling

Introspection means the schema is queryable. GraphiQL gives you autocomplete and inline docs in the browser. Codegen generates type-safe TypeScript hooks (useGetUserQuery) so the wire shape and the React component's types are guaranteed to match.

Where It Hurts

The Real Problems

Caching Is Hard

Everything is POST /graphql with a different body. CDN and browser HTTP caches see one URL — they can't help. Solutions: persisted queries (server stores the query, client sends a hash, request becomes cacheable GET), client-side normalized caches (Apollo, Relay, urql), or bolt on Automatic Persisted Queries to recover REST-style edge caching.

The N+1 Problem on the Server

A query for "10 users and their orders" calls the user resolver once, then the order resolver 10 times — naive resolvers turn one query into dozens of database hits. The fix is the DataLoader pattern: batch and de-duplicate within a single request. Every serious GraphQL backend uses it; forgetting it is how prod databases fall over.

Easy to Write a Query That Nukes the DB

A client can request deeply nested fields, or 100,000 users at once. Defenses: query depth limits, complexity scoring, persisted-only queries in production (clients can only run pre-registered queries), per-operation rate limits.

File Uploads, Errors, and HTTP Semantics
  • Uploads: not part of the spec. Use graphql-multipart-request-spec or pre-signed URLs to S3 instead.
  • Errors: GraphQL almost always returns 200 OK with errors in the body. HTTP-level monitoring lies; instrument GraphQL errors separately.
  • Status codes & auth: you give up REST's free use of 401, 403, 429, etc. Auth and rate limits live in resolvers and middleware.
Subscriptions Are Heavy

Real-time GraphQL runs over WebSocket (or SSE via graphql-sse). You inherit all the WebSocket ops complexity — connection lifecycle, sticky sessions, multi-node fan-out via Redis. Often simpler to use SSE or a dedicated pub/sub service for real-time and keep GraphQL synchronous.

At Scale

Federation and Beyond

Apollo Federation (and the open GraphQL Federation spec) lets multiple backend services own different parts of one unified schema. The gateway stitches sub-graphs together — Users service owns the User type, Orders service owns Order and extends User with an orders field. Clients see one graph; teams own slices.

It's the natural endpoint of "GraphQL as the API layer over many microservices." Comes with operational weight — schema composition, change management, graph governance — that pays off only at scale.

Decision

When to Pick GraphQL

  • Your client renders nested data from many backends in one shot — mobile apps, complex SPAs, dashboards.
  • You have multiple client types (web, iOS, Android) with different field needs against the same data.
  • You want a strongly-typed contract with first-class introspection and codegen.
  • Aggregating across several internal services is a recurring task that's currently smeared across BFFs.

Skip GraphQL for: simple public APIs (REST is friendlier to outsiders), file-heavy workloads, anything where CDN caching matters more than client-flexibility, and small teams without the bandwidth to operate DataLoader, persisted queries, and complexity limits properly.

Continue

Other API Styles