Why Facebook Invented GraphQL
GraphQL and gRPC Foundations address two major problems that traditional REST APIs can face at scale: inefficient data fetching for clients and heavy communication overhead between internal services. 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, and 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, ~200msGraphQL: 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.
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.
