TechLead
Lesson 7 of 20
5 min read
GraphQL

GraphQL vs REST

Compare GraphQL and REST APIs in depth, understanding the trade-offs, strengths, and ideal use cases for each approach

The API Paradigm Debate

REST has been the dominant API paradigm for over a decade, and GraphQL has emerged as a powerful alternative. Understanding when to use each — and when to combine them — is critical for modern API design. This is not about picking a winner; it is about choosing the right tool for the job.

Side-by-Side Comparison

Aspect REST GraphQL
EndpointsMultiple endpoints (/users, /posts)Single endpoint (/graphql)
Data fetchingServer decides response shapeClient decides response shape
Over-fetchingCommon — endpoint returns all fieldsEliminated — client requests exact fields
Under-fetchingCommon — requires multiple requestsEliminated — fetch related data in one query
VersioningURL versioning (/api/v1, /api/v2)Schema evolution — no versioning needed
CachingHTTP caching built-in (ETags, Cache-Control)Requires client-side caching (Apollo Cache)
Type systemOpenAPI/Swagger (optional)Built-in, mandatory schema
Real-timeRequires WebSocket or SSE separatelySubscriptions are part of the spec
File uploadsNative multipart supportRequires special handling

The Over-Fetching Problem

Over-fetching occurs when an API returns more data than the client needs. This wastes bandwidth and processing time, especially on mobile devices:

// REST: Fetch user profile — returns ALL fields
// GET /api/users/42
{
  "id": 42,
  "name": "Alice",
  "email": "alice@example.com",
  "bio": "Long bio text...",
  "avatarUrl": "...",
  "phone": "+1-555-0123",
  "address": { "street": "...", "city": "...", "country": "..." },
  "preferences": { ... },
  "createdAt": "2024-01-01",
  "updatedAt": "2025-03-15",
  "lastLoginAt": "2025-04-05"
  // 20+ more fields the mobile app doesn't need
}
# GraphQL: Fetch only what the mobile header needs
query MobileUserHeader {
  user(id: "42") {
    name
    avatarUrl
  }
}
# Response: { "data": { "user": { "name": "Alice", "avatarUrl": "..." } } }

The Under-Fetching Problem

Under-fetching requires multiple round-trips to gather related data. This is particularly painful on slow mobile connections:

// REST: Building a blog post page requires 3+ requests
// Request 1: GET /api/posts/1
const post = await fetch('/api/posts/1').then(r => r.json());

// Request 2: GET /api/users/42 (the author)
const author = await fetch(`/api/users/${post.authorId}`).then(r => r.json());

// Request 3: GET /api/posts/1/comments
const comments = await fetch('/api/posts/1/comments').then(r => r.json());

// Request 4: GET /api/users/5, GET /api/users/8 (comment authors)
const commentAuthors = await Promise.all(
  comments.map(c => fetch(`/api/users/${c.authorId}`).then(r => r.json()))
);
// Total: 4+ HTTP round-trips, high latency on mobile
# GraphQL: One request gets everything
query BlogPostPage {
  post(id: "1") {
    title
    body
    publishedAt
    author {
      name
      avatarUrl
      bio
    }
    comments {
      text
      createdAt
      author {
        name
        avatarUrl
      }
    }
    tags {
      name
      slug
    }
  }
}
# Total: 1 HTTP request

Where REST Excels

REST Strengths

  • HTTP Caching: REST APIs benefit from the entire HTTP caching infrastructure — CDNs, browser cache, ETags, and Cache-Control headers work out of the box
  • Simplicity: For simple CRUD APIs with few relationships, REST is straightforward and well-understood
  • File Uploads: Multipart form data is natively supported in REST; GraphQL requires workarounds
  • Webhooks: REST endpoints are natural targets for third-party webhook integrations
  • Browser-friendly: REST APIs can be tested directly in a browser address bar
  • Maturity: Decades of tooling, middleware, and best practices

Where GraphQL Excels

GraphQL Strengths

  • Complex Data Requirements: When views need data from multiple related resources, GraphQL eliminates the waterfall of REST requests
  • Multiple Client Platforms: Mobile, web, and TV apps can each request exactly the data they need without custom endpoints
  • Rapid Frontend Iteration: Frontend developers can change data requirements without waiting for backend changes
  • Strong Typing: The schema is the contract, enabling code generation, validation, and self-documenting APIs
  • Real-time: Subscriptions are a first-class feature, not bolted on
  • Developer Experience: GraphiQL, introspection, and auto-generated docs make exploration easy

Hybrid Approach

Many production systems use both GraphQL and REST together. This is often the most pragmatic approach:

// Common hybrid architecture
// GraphQL for complex reads
// POST /graphql
query DashboardData {
  currentUser { name role notifications { ... } }
  recentPosts { ... }
  analytics { ... }
}

// REST for simple operations
// POST /api/upload (file upload)
// GET /api/health (health check)
// POST /api/webhooks/stripe (webhook receiver)
// GET /api/export/csv (file download)

Decision Framework

  • Choose REST when: Simple CRUD, heavy caching needs, file operations, third-party integrations, or your team is already experienced with REST
  • Choose GraphQL when: Complex data relationships, multiple client platforms, rapid frontend iteration, real-time requirements, or microservice aggregation
  • Choose both when: Most real-world applications benefit from using GraphQL for complex reads and REST for simple operations, uploads, and webhooks

Continue Learning