API design comparison

REST vs GraphQL

Two different ways to design an HTTP API. Choosing between them is one of the most discussed architectural decisions of the last decade — and one of the most common topics in code reviews and system-design interviews.

TL;DR

  • REST exposes resources at stable URLs (one URL per resource type). Clients call multiple endpoints to assemble what they need. Great for simple, cacheable, public APIs.
  • GraphQL exposes a single endpoint with a typed schema. Clients write a query describing exactly the data they want. Great for product APIs powering many frontends with different data needs.
  • Neither is universally better. The choice depends on your client diversity, caching needs, schema evolution discipline, and team experience.

Side-by-side comparison

AspectRESTGraphQL
ShapeMultiple URL endpoints per resourceSingle endpoint, query-driven
Data fetchingFixed response per endpoint; over- or under-fetching commonClient picks exact fields → no over-fetching
Verbs / methodsHTTP verbs: GET, POST, PUT, PATCH, DELETEQuery, Mutation, Subscription (over POST or WebSocket)
Type systemOptional (OpenAPI / JSON Schema)Built-in, mandatory schema (SDL)
Versioning/v1/, /v2/ in URL or headerSchema evolution + @deprecated
CachingHTTP caching out of the box (CDN-friendly)Normalised client caches; harder on the wire
Error handlingHTTP status codes (4xx / 5xx)Always 200 OK; errors in "errors" array
N+1 problemClient orchestrates calls (front-end sees it)Resolvers expose it on the server (DataLoader pattern)
ToolingMature: Swagger, Postman, curlStrong: GraphiQL, Apollo Studio, codegen
Learning curveLow — HTTP knowledge is enoughHigher — schema design, resolvers, federation
Best forPublic APIs, partner integrations, file uploadsProduct APIs, mobile + web sharing one backend

Code side-by-side

Fetching a user with their last 5 orders:

REST (often 2 calls)

GET /api/users/42
→ { "id": 42, "name": "Alice", "email": "..." }

GET /api/users/42/orders?limit=5
→ [
    { "id": 901, "total": 42.00, "createdAt": "..." },
    { "id": 887, "total": 19.50, "createdAt": "..." },
    ...
  ]

GraphQL (one call)

POST /graphql
{
  user(id: 42) {
    name
    email
    orders(limit: 5) {
      id
      total
      createdAt
    }
  }
}

When to use REST

  • Public API consumed by third parties. REST is the lingua franca — every language has an HTTP client; every developer knows GET/POST.
  • You need HTTP caching. Static-ish resources cached at the CDN edge are dramatically cheaper than running every query through your servers.
  • File uploads / downloads. GraphQL handles these awkwardly; multipart uploads via REST are simpler.
  • Webhooks and event delivery. Outbound events to partner systems are almost always REST POST callbacks.
  • Small team, no GraphQL experience. REST has lower ramp-up cost and fewer footguns.

When to use GraphQL

  • Multiple clients with different data needs. Mobile, web, and partner apps can each ask for what they need without separate endpoints.
  • Aggregating multiple backend resources. A GraphQL layer becomes a thin orchestration on top of microservices.
  • Strong schema discipline desired. The mandatory schema becomes the contract between teams; codegen produces typed clients automatically.
  • Rapid product iteration. Adding fields without releasing new endpoints reduces deploy coupling.
  • Federated architecture. Multiple teams own subgraphs that compose into one supergraph (Apollo Federation, Hot Chocolate, etc.).

English phrases engineers use

REST conversations

  • "We expose an endpoint at /api/users/:id."
  • "This returns a 404 if the resource is missing."
  • "The response is idempotent — same input, same output."
  • "Let's version the API behind /v2/."
  • "The endpoint is over-fetching — the mobile app only needs three of the twelve fields."

GraphQL conversations

  • "We have a schema-first approach — the SDL is the source of truth."
  • "The resolver fetches related orders from the orders service."
  • "We're hitting N+1 on the comments resolver — let's add a DataLoader."
  • "The field is deprecated with @deprecated(reason: ...) — clients have 60 days to migrate."
  • "This is a breaking change on the schema — we'll need a coordinated rollout."

Quick decision tree

  • Public API consumed by external partners → REST
  • Need aggressive HTTP/CDN caching → REST
  • One backend, many frontends with different data needs → GraphQL
  • Mobile-first product where round trips hurt → GraphQL
  • Many microservices, want a single client API → GraphQL (Federation)
  • Team has no GraphQL experience and a tight deadline → REST
  • Need file uploads → REST (or hybrid)

Frequently asked questions

What is the main difference between REST and GraphQL in plain English?

REST organises an API around resources (URLs like /users/42), and clients call separate endpoints to fetch related data. GraphQL exposes a single endpoint and lets clients describe exactly the shape of the data they want in one query — including nested resources.

When should I use REST instead of GraphQL?

Use REST when your API is simple and resource-shaped (CRUD on a few entities), when HTTP caching matters (REST plays well with CDNs), when consumers are external partners who expect a conventional REST API, or when your team has no in-house GraphQL experience.

When is GraphQL the better choice?

Pick GraphQL when clients (mobile, multiple frontends) need to compose data from many backend resources and want to avoid over-fetching; when you have a typed schema you want to share across teams; or when you need strong client-side tooling (auto-generated types, IDE autocomplete).