Skip to main content

πŸ”· GraphQL vs. REST Architecture

REST built the modern web, but it makes the client fetch data on the server's terms. GraphQL flips that: the client asks for exactly the shape it needs, in one request, against one strongly-typed endpoint. This lesson gives you a clear mental model of both, the real trade-offs, and how to decide which one fits a given problem.

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Explain what GraphQL is and the problems it was designed to solve
  • Diagnose over-fetching, under-fetching, and the N+1 request patterns in REST
  • Describe GraphQL's core principles β€” a single typed endpoint, declarative fetching, and introspection
  • Compare REST and GraphQL and choose the right one for a given scenario
  • Identify the major tools in the GraphQL ecosystem

Estimated Time: 30–40 minutes  β€’  Difficulty: Intermediate

Hands-on: Rewrite a multi-request REST feature as a single GraphQL query.

In This Lesson

What Is GraphQL?

GraphQL is a query language for APIs and a runtime that executes those queries against your data. It was created at Facebook in 2012 to power their mobile apps, open-sourced in 2015, and is now governed by the vendor-neutral GraphQL Foundation. Crucially, it is a specification, not a specific piece of software β€” you can implement or consume it in any language.

The one idea to hold onto: with GraphQL the client describes the data it wants, and the server returns exactly that β€” no more, no less β€” as a JSON response shaped like the request.

πŸ’‘ A shopping analogy. A REST API is like a row of specialty shops: you go to the bakery for bread, the butcher for meat, and the greengrocer for vegetables β€” several trips to several counters. GraphQL is like handing a single personal shopper your whole list; they make one trip and bring back precisely what you asked for.

πŸ“– Key Terms

Endpoint: a URL a client sends requests to. REST APIs expose many; GraphQL usually exposes exactly one (commonly /graphql).

Over-fetching: the server returns fields the client never uses.

Under-fetching: one response isn't enough, so the client must make additional requests to complete the picture.

Where REST Strains

REST (Representational State Transfer) has been the default API style for two decades, and for good reason: it maps cleanly onto HTTP, benefits from HTTP caching, and is simple to reason about. But as UIs grew more data-hungry and clients diversified (web, iOS, Android, smart TVs), a few recurring pain points emerged.

graph TD A[Common REST pain points] --> B[Over-fetching: more fields than the UI needs] A --> C[Under-fetching: many round trips to assemble one screen] A --> D[Endpoint sprawl: clients must know many URLs] A --> E[Versioning: /v1, /v2 to evolve safely] A --> F[Docs drift from the actual responses]

Over-fetching and under-fetching

Say a mobile list only needs each user's name and avatar. A REST GET /api/users typically returns the entire user record β€” email, bio, timestamps, settings β€” wasting bandwidth on a metered connection. That's over-fetching. Conversely, to render one profile screen you might need the user, their recent posts, and their followers β€” three endpoints, three round trips. That's under-fetching.

The N+1 request problem

Under-fetching compounds badly in lists. Suppose you want to show 20 blog posts, each with its comments:

GET /api/posts            # 1 request β†’ returns 20 posts
GET /api/posts/1/comments # + 1 request
GET /api/posts/2/comments # + 1 request
...                       # ...one per post
GET /api/posts/20/comments

That's 1 + 20 = 21 requests just to paint one screen β€” the classic N+1 pattern. Each request carries its own latency, headers, and connection overhead. GraphQL lets the client express the whole nested need in a single request, and it becomes the server's job to fetch it efficiently.

⚠️ REST is not "wrong"

These are pressures, not defects. For simple resource CRUD, file uploads, or public APIs that lean on HTTP caching, REST is often the better choice. GraphQL trades some of REST's simplicity and free caching for flexibility β€” a trade that only pays off when your data needs are genuinely varied and nested.

GraphQL's Core Principles

GraphQL addresses those pressures through a handful of deliberate design choices:

  • Declarative data fetching β€” the client states the exact fields it wants; the response mirrors that shape.
  • A single endpoint β€” every operation is a POST to one URL (typically /graphql), so there are no endpoint maps to memorize.
  • A strong type system β€” a schema declares every type and field, giving you validation, editor autocomplete, and a living contract.
  • Introspection β€” the API can be queried for its own schema, which powers tooling like GraphiQL and Apollo Sandbox.
  • Hierarchical & composable β€” queries nest to match your UI's component tree, and fragments let you reuse selections.
How a GraphQL request is served A client sends one query to a single GraphQL server, which resolves each requested field against one or more data sources and returns exactly the requested data. Client one typed query GraphQL server resolves each field Database REST / service Cache query exact data
Figure 1 β€” One query enters a single endpoint; the server resolves each field from whatever sources it needs and returns a response shaped like the request.

A Side-by-Side Comparison

Consider building a social profile screen that shows a user, their posts, and their friends.

The REST approach

GET /api/users/123
GET /api/users/123/posts
GET /api/users/123/friends

Three round trips, each returning a full record, and the client stitches the pieces together.

The GraphQL approach

query ProfilePage($id: ID!) {
  user(id: $id) {
    name
    email
    posts {
      title
      createdAt
    }
    friends {
      name
      avatarUrl
    }
  }
}

One request names exactly the fields the screen renders. The response comes back in the same shape:

Response

{
  "data": {
    "user": {
      "name": "Ada Lovelace",
      "email": "ada@example.com",
      "posts": [
        { "title": "On Analytical Engines", "createdAt": "2026-05-01" }
      ],
      "friends": [
        { "name": "Charles Babbage", "avatarUrl": "/img/cb.png" }
      ]
    }
  }
}
REST versus GraphQL for one profile screen The REST side shows three separate requests that the client must combine; the GraphQL side shows a single request returning exactly the requested data. REST GET /users/123 GET /users/123/posts GET /users/123/friends Client stitches three responses together GraphQL POST /graphql user(id) { name, email, posts { title }, friends { name } } Exactly the requested data, one response
Figure 2 β€” Same result, different shape of work: three combined requests on the left, one precise request on the right.

Choosing Between Them

Neither wins outright. Match the tool to the shape of the problem.

Reach for GraphQL when… Reach for REST when…
Screens need deeply nested, related data You do simple CRUD on single resources
Many clients each need different field sets You lean heavily on HTTP/CDN caching
You aggregate data from several back ends You handle binary uploads or file streaming
Bandwidth is precious (mobile) The API is small with a handful of endpoints
Requirements change often and the UI evolves fast You want to reuse mature REST infrastructure

πŸ’‘ Hybrid is common and healthy

Plenty of teams run both: GraphQL for the product-facing app where data needs are varied, and REST (or gRPC) for internal service-to-service calls, webhooks, and file endpoints. Choosing GraphQL is not an all-or-nothing migration.

The GraphQL story shows up at scale, too. GitHub's REST v3 API exposed dozens of endpoints for repositories alone; its GraphQL API consolidated access behind one schema and let clients fetch precisely the fields a page renders. Shopify, Netflix, and others report similar gains in front-end simplicity β€” though all of them also pay GraphQL's costs in caching complexity and query-cost management.

The GraphQL Ecosystem

Because GraphQL is a spec, a healthy ecosystem of implementations exists across languages and both sides of the wire:

graph TD A[GraphQL ecosystem] --> B[Clients] A --> C[Servers] A --> D[Dev tools] B --> B1[Apollo Client] B --> B2[Relay] B --> B3[urql] C --> C1[Apollo Server] C --> C2[GraphQL Yoga] C --> C3[Pothos / Nexus schema builders] D --> D1[GraphiQL] D --> D2[Apollo Sandbox] D --> D3[GraphQL Code Generator]

πŸ“– Note on tooling names

You may still see references to GraphQL Playground; it is now deprecated in favor of GraphiQL and Apollo Sandbox. Likewise, the standalone apollo-server package has been superseded by @apollo/server (v4+). We use the current packages throughout this module.

Hands-on Exercise

πŸ‹οΈ Collapse a REST feature into one GraphQL query

Objective: Turn a multi-request REST feature into a single declarative query and reflect on the trade-offs.

Instructions:

  1. Pick a real feature β€” an e-commerce product page is a good one.
  2. List the REST endpoints it would call today (product, reviews, related items, stock).
  3. Write one GraphQL query that returns everything the page renders, and nothing it doesn't.
  4. In two sentences, note one advantage and one drawback of the GraphQL version for this feature.
πŸ’‘ Hint

Think in terms of the page's component tree: the product card, the reviews list (each with its author), a "related products" strip, and an availability badge. Each nested UI piece maps to a nested selection set.

βœ… Sample solution

REST today:

GET /api/products/123
GET /api/products/123/reviews
GET /api/products/123/related
GET /api/inventory/product/123

One GraphQL query:

query ProductPage($id: ID!) {
  product(id: $id) {
    name
    price
    description
    images { url alt }
    reviews {
      rating
      comment
      user { name }
    }
    relatedProducts {
      id
      name
      price
      thumbnail
    }
    inventory {
      inStock
      availableSizes
      shippingEstimate
    }
  }
}

Advantage: one round trip returns exactly the fields the page needs, ideal on mobile. Drawback: you lose free per-endpoint HTTP caching, so you must add query-level caching and guard against expensive nested queries.

Quiz

🎯 Check Your Understanding

Question 1: A mobile list needs only each user's name, but GET /api/users returns the full record every time. What is this called?

Question 2: Which statement about GraphQL endpoints is accurate?

Question 3: For which scenario is plain REST usually the better fit?

Summary

πŸŽ‰ Key Takeaways

  • GraphQL is a spec: the client declares the exact fields it wants and the response mirrors that shape.
  • It targets REST's over-fetching, under-fetching, and N+1 patterns with one typed endpoint.
  • Its pillars are declarative fetching, a single endpoint, a strong type system, and introspection.
  • REST still wins for simple CRUD, file transfers, and cache-heavy public APIs β€” hybrid setups are normal.
  • The ecosystem is mature: Apollo Client/Server, urql, Relay, GraphQL Yoga, GraphiQL, and Code Generator.

πŸ“š Further Reading

πŸš€ What's Next?

Now that you know why GraphQL exists, the next lesson β€” Schema Definition and Types β€” dives into the schema itself: the strongly-typed contract that makes all of this possible.

πŸŽ‰ Nice work!

You can now explain GraphQL, spot REST's pain points, and pick the right tool for a job. Time to design the schema.