Skip to content
GraphQL and gRPC Foundations: Beyond REST 4 min

GraphQL and gRPC Foundations: Beyond REST

SD
ScaleDojo
May 11, 2026
4 min read948 words
GraphQL and gRPC Foundations: Beyond REST

Why Facebook Invented GraphQL

In 2012, Facebook was rebuilding its mobile app. The REST API returned massive JSON payloads - a single news feed call fetched 30+ fields per post when the mobile app only needed 5. On 2G networks in emerging markets, this killed load times. Meanwhile, the feed screen required 6 separate REST calls (posts, likes, comments, user profiles, photos, ads) creating a waterfall of round trips. Facebook built GraphQL to solve both: one request, exactly the data needed. Two years later, Google faced the opposite problem - internal microservices were drowning in JSON parsing overhead. They built gRPC with binary Protocol Buffers, achieving 10x serialization speedups. Today, most large-scale systems use all three: REST for public APIs, GraphQL for client-facing data, gRPC for internal service-to-service calls.

REST's Pain Points at Scale

The Over-Fetching Problem:

  Mobile app needs: { name, avatar }

  GET /api/users/42
  Response (2.4 KB):
  {
    "id": 42,
    "name": "Alice",
    "avatar": "...",
    "email": "...",       // don't need
    "phone": "...",       // don't need
    "address": {...},     // don't need (500 bytes)
    "preferences": {...}, // don't need (800 bytes)
    "created_at": "...",  // don't need
    ... 25 more fields    // don't need
  }
  Wasted: ~2 KB per request x 1M users = 2 GB/day wasted bandwidth

The Under-Fetching Problem:

  Profile page needs: user + posts + followers + photos

  Request 1: GET /users/42           (120ms)
  Request 2: GET /users/42/posts     (200ms)  // waits for #1
  Request 3: GET /users/42/followers (150ms)  // waits for #1
  Request 4: GET /users/42/photos    (180ms)  // waits for #1
  Request 5: GET /posts/99/comments  (100ms)  // waits for #2
  Total: 5 round trips, ~750ms on mobile

  GraphQL equivalent: 1 round trip, ~200ms

GraphQL: Query Exactly What You Need

GraphQL Query (what the client sends):

  query UserProfile {
    user(id: 42) {
      name
      avatar
      posts(last: 5) {
        title
        likeCount
        comments(first: 3) {
          author { name }
          body
        }
      }
      followers {
        totalCount
      }
    }
  }

GraphQL Response (exactly what was asked):

  {
    "data": {
      "user": {
        "name": "Alice",
        "avatar": "https://cdn.example.com/42.jpg",
        "posts": [
          {
            "title": "System Design Tips",
            "likeCount": 234,
            "comments": [
              { "author": { "name": "Bob" }, "body": "Great post!" }
            ]
          }
        ],
        "followers": { "totalCount": 1523 }
      }
    }
  }

  1 request. Exactly the fields needed. No wasted bytes.

GraphQL Architecture

How GraphQL Works on the Server:

  Client --query--> [GraphQL Server] --resolvers--> Data Sources
                         |
                    Schema Definition
                    (type system)

  Schema (defines what is queryable):

    type User {
      id: ID!
      name: String!
      avatar: String
      posts(last: Int): [Post!]!
      followers: FollowerConnection!
    }

    type Post {
      id: ID!
      title: String!
      likeCount: Int!
      comments(first: Int): [Comment!]!
    }

    type Query {
      user(id: ID!): User
      posts(limit: Int, offset: Int): [Post!]!
    }

  Resolvers (fetch data per field):

    Query.user(id) -> SELECT * FROM users WHERE id = ?
    User.posts(user) -> SELECT * FROM posts WHERE author_id = ?
    Post.comments(post) -> SELECT * FROM comments WHERE post_id = ?

  N+1 Problem: 10 posts x 1 comments query each = 11 DB queries
  Solution: DataLoader batches them into 1 query:
    SELECT * FROM comments WHERE post_id IN (1,2,3,4,5,6,7,8,9,10)

gRPC: Binary Speed for Microservices

Protocol Buffer Definition (.proto file):

  syntax = "proto3";

  service UserService {
    rpc GetUser(GetUserRequest) returns (User);
    rpc ListUsers(ListUsersRequest) returns (stream User);
    rpc UpdateUser(User) returns (User);
  }

  message User {
    int64 id = 1;
    string name = 2;
    string email = 3;
    repeated Post posts = 4;
  }

Why gRPC is Fast:

  JSON (REST):     { "id": 42, "name": "Alice" }  =  35 bytes + parsing
  Protobuf (gRPC): 08 2A 12 05 41 6C 69 63 65     =  9 bytes, zero parsing

  Feature          REST/JSON       gRPC/Protobuf
  ----------------  ---------------  ----------------
  Serialization    Text (slow)      Binary (3-10x faster)
  Transport        HTTP/1.1         HTTP/2 (multiplexed)
  Contract         OpenAPI (docs)   .proto (code-generated)
  Streaming        SSE/WebSocket    Native (4 modes)
  Browser support  Native           Needs grpc-web proxy
  Debugging        curl friendly    Needs special tools

gRPC Streaming Modes:

  1. Unary:           Client sends 1, Server returns 1     (like REST)
  2. Server streaming: Client sends 1, Server streams many  (live feed)
  3. Client streaming: Client streams many, Server returns 1 (file upload)
  4. Bidirectional:    Both stream simultaneously            (chat/gaming)

When to Use Each Protocol

Protocol Selection Guide:

  Use Case                      Best Choice   Why
  ----------------------------  -----------   --------------------------
  Public API (external devs)    REST          Universal, cacheable, simple
  Mobile app data fetching      GraphQL       Bandwidth-efficient, flexible
  Microservice-to-microservice  gRPC          Fast, type-safe, streaming
  Browser real-time updates     GraphQL Sub   Built-in subscription model
  File uploads                  REST          Multipart is well-supported
  Internal event streaming      gRPC          Bidirectional streaming
  Third-party integrations      REST          Everyone understands REST
  Complex nested data queries   GraphQL       Single round trip
  ML model serving              gRPC          Low latency, binary data

Real-World Combinations:

  Netflix:  REST (public) + GraphQL (BFF) + gRPC (internal)
  Shopify:  REST (public) + GraphQL (storefront API)
  Google:   REST (public) + gRPC (all internal services)
  GitHub:   REST v3 (legacy) + GraphQL v4 (new clients)
  Uber:     REST (rider/driver apps) + gRPC (internal ~4000 services)

Interview Tip

When discussing API protocols in interviews, demonstrate you understand tradeoffs, not just definitions. Say: 'REST is my default for public APIs because it is universally understood and cacheable. For mobile or complex frontend data needs, I would add a GraphQL layer (or BFF) to eliminate round trips and over-fetching. For internal service communication - especially when latency matters - gRPC with Protobuf gives 3-10x faster serialization. Many companies like Netflix use all three at different layers.' Always mention the GraphQL N+1 problem and DataLoader as the solution - it shows depth.

<
GraphQL and gRPC Foundations: Beyond REST - Architecture Diagram
Architecture overview
/blockquote>

Key Takeaway

REST is simple and universal but suffers from over/under-fetching at scale. GraphQL lets clients request exactly what they need in one round trip - ideal for mobile and complex UIs. gRPC uses binary Protobuf and HTTP/2 for 3-10x faster service-to-service communication with native streaming. Most large systems combine all three at different layers. Choose based on the communication boundary: REST for external, GraphQL for client-facing, gRPC for internal.

Enjoyed this article?

Share it with your network to help others level up their system design skills.

Discussion0

Join the Discussion

Sign in to leave comments, reply to others, or like insights.

Sign In to ScaleDojo

No comments yet. Be the first to start the thread!

Related Articles

Enjoyed this content?

Your support keeps us creating free resources

We put a lot of hours into researching and writing these guides. If it helped you, consider buying us a coffee. Every bit goes toward keeping ScaleDojo's content free and growing.

$

One-time payment via Stripe. ScaleDojo account required.

ScaleDojo Logo
Initializing ScaleDojo