Skip to main content
Career Paths
Concepts
Bep Api Protocols
The Simplified Tech

Role-based learning paths to help you master cloud engineering with clarity and confidence.

Product

  • Career Paths
  • Interview Prep
  • Scenarios
  • AI Features
  • Cloud Comparison
  • Resume Builder
  • Pricing

Community

  • Join Discord

Account

  • Dashboard
  • Credits
  • Updates
  • Sign in
  • Sign up
  • Contact Support

Stay updated

Get the latest learning tips and updates. No spam, ever.

Terms of ServicePrivacy Policy

© 2026 TheSimplifiedTech. All rights reserved.

BackBack
Interactive Explainer

API Protocols: REST vs GraphQL vs gRPC

Choose the right communication contract before you write a single line of code

🎯Key Takeaways
REST is the default: stateless, HTTP-native, universally understood. Use it unless you have a specific reason not to.
GraphQL solves over/under-fetching for complex UIs but adds schema management and N+1 complexity.
gRPC wins on performance for internal microservice communication — 5–10× faster than REST with HTTP/2 + protobuf.
The FAANG pattern: REST or GraphQL for public APIs, gRPC for internal services.
Changing protocols after clients are in production costs 6–18 months. Choose deliberately upfront.

API Protocols: REST vs GraphQL vs gRPC

Choose the right communication contract before you write a single line of code

~7 min read
Be the first to complete!
What you'll learn
  • REST is the default: stateless, HTTP-native, universally understood. Use it unless you have a specific reason not to.
  • GraphQL solves over/under-fetching for complex UIs but adds schema management and N+1 complexity.
  • gRPC wins on performance for internal microservice communication — 5–10× faster than REST with HTTP/2 + protobuf.
  • The FAANG pattern: REST or GraphQL for public APIs, gRPC for internal services.
  • Changing protocols after clients are in production costs 6–18 months. Choose deliberately upfront.

Lesson outline

Why Your Protocol Choice Ships With You Forever

In 2014, Netflix was serving 40% of peak North American internet traffic through a single monolithic API. When they broke it apart, they had to choose: REST, the battle-tested standard? Or something new? They chose a custom solution that eventually influenced GraphQL.

The Protocol Trap

Changing your API protocol after clients are in production costs 6–18 months of migration work. At Uber in 2016, switching internal services from REST to gRPC took 2 years and 3 full engineering teams.

The three dominant protocols each solve a different fundamental problem:

ProtocolSolvesBest ForAvoid When
RESTResource exposure over HTTPPublic APIs, simple CRUD, mobile appsHigh-throughput internal services
GraphQLOver/under-fetchingComplex UIs needing flexible queriesSimple APIs, non-graph data models
gRPCHigh-performance RPCInternal microservices, streamingPublic-facing APIs, browser clients

REST: The Universal Language of the Web

REST (Representational State Transfer) is not a protocol — it's an architectural style. Roy Fielding defined 6 constraints in his 2000 dissertation. Most "REST APIs" violate at least 3 of them.

The 6 REST Constraints (and which ones matter at FAANG)

  • ✅Stateless — Every request contains all needed info. No session state on server. This enables horizontal scaling.
  • ✅Uniform Interface — Resources = nouns (GET /users/123). Verbs = HTTP methods. This is the constraint teams actually follow.
  • ✅Client-Server separation — UI and data storage are decoupled. Mobile app doesn't care if you switch databases.
  • ⚠️Cacheable — Responses should declare cacheability. Most teams forget this, causing massive CDN misuse.
  • 🚫Layered System — Client doesn't know if it's talking to origin or proxy. Often ignored.
  • 🚫Code on Demand — Servers can send executable code. Almost never used.

Richardson Maturity Model

Level 0: RPC-style (POST /getUserData). Level 1: Resources (/users/123). Level 2: HTTP verbs + status codes. Level 3: HATEOAS links. Most production APIs are Level 2. Level 3 is theoretical.

rest-api-design.ts
1// REST: Resource-oriented design
2// ✅ Good REST design — nouns, proper verbs, status codes
3import express from 'express';
4
5const router = express.Router();
6
7// GET /users/:id — fetch single resource
8router.get('/users/:id', async (req, res) => {
9 const user = await db.users.findById(req.params.id);
Always return 404 for missing resources — not 200 with null body
10 if (!user) return res.status(404).json({ error: 'User not found' });
11 return res.status(200).json(user);
12});
13
14// POST /users — create resource (returns 201 Created)
15router.post('/users', async (req, res) => {
201 Created signals to clients they can fetch the new resource
16 const user = await db.users.create(req.body);
17 return res.status(201).json(user); // 201, not 200
18});
19
20// PATCH /users/:id — partial update (not PUT which replaces)
PATCH for partial update; PUT replaces the entire resource
21router.patch('/users/:id', async (req, res) => {
22 const user = await db.users.update(req.params.id, req.body);
23 return res.status(200).json(user);
24});
25
204 No Content is idiomatic for successful DELETE
26// DELETE /users/:id — idempotent deletion
27router.delete('/users/:id', async (req, res) => {
28 await db.users.delete(req.params.id);
29 return res.status(204).send(); // 204 No Content
30});
31
32// ❌ Common REST mistakes
33// POST /getUser — verb in URL
34// GET /users/delete/123 — action in URL
35// DELETE /users with 200 — wrong status code

GraphQL: Ask for Exactly What You Need

Facebook built GraphQL in 2012 because their mobile News Feed was making 6+ REST calls on startup, getting 10× more data than needed. GraphQL solved both problems simultaneously.

How a GraphQL Query Executes (what happens under the hood)

→

01

Client sends a query document to POST /graphql — a single endpoint

→

02

Server parses the query into an AST (abstract syntax tree)

→

03

Resolver functions execute for each field in the selection set

→

04

DataLoader batches N+1 database calls into single queries

05

Response returns only the exact fields requested — no more, no less

1

Client sends a query document to POST /graphql — a single endpoint

2

Server parses the query into an AST (abstract syntax tree)

3

Resolver functions execute for each field in the selection set

4

DataLoader batches N+1 database calls into single queries

5

Response returns only the exact fields requested — no more, no less

The N+1 Problem — GraphQL's Achilles Heel

Without DataLoader, querying 100 users and their posts makes 101 DB calls (1 for users + 1 for each user's posts). Always use DataLoader or a query batching library in production.

FeatureRESTGraphQL
EndpointsMany (/users, /posts, /comments)One (/graphql)
Response shapeFixed by serverDefined by client
Type systemOptional (OpenAPI)Built-in (mandatory)
Real-timePolling or SSESubscriptions (WebSocket)
CachingHTTP cache works perfectlyComplex (POST by default)
Learning curveLowHigh (schema, resolvers, N+1)
graphql-schema.ts
1// GraphQL: Schema-first design with resolvers
2import { makeExecutableSchema } from '@graphql-tools/schema';
3import DataLoader from 'dataloader';
4
5// 1. Define the schema (this is your API contract)
6const typeDefs = `
Schema is the contract. Change it carefully — breaking changes break all clients
7 type User {
8 id: ID!
9 name: String!
10 email: String!
11 posts: [Post!]! # relationship resolved lazily
12 }
13
14 type Post {
15 id: ID!
16 title: String!
17 author: User!
18 }
19
20 type Query {
21 user(id: ID!): User
22 users(limit: Int = 20): [User!]!
23 }
24
25 type Mutation {
26 createPost(title: String!, authorId: ID!): Post!
27 }
28`;
DataLoader batches all userLoader.load() calls within one tick into a single DB query
29
30// 2. DataLoader prevents N+1 queries
31const userLoader = new DataLoader(async (userIds: readonly string[]) => {
32 const users = await db.users.findMany({ where: { id: { in: [...userIds] } } });
33 return userIds.map(id => users.find(u => u.id === id) ?? null);
34});
35
36// 3. Resolvers — field-level functions
37const resolvers = {
38 Query: {
39 user: (_: unknown, { id }: { id: string }) => db.users.findById(id),
40 users: (_: unknown, { limit }: { limit: number }) => db.users.findMany({ limit }),
41 },
42 User: {
Without DataLoader here, 100 posts = 100 DB calls. With it = 1 batch query
43 // Called once per User, but DataLoader batches the DB calls
44 posts: (user: User) => db.posts.findByAuthorId(user.id),
45 },
46 Post: {
47 author: (post: Post) => userLoader.load(post.authorId), // batched!
48 },
49};

gRPC: Built for Microservices at Scale

Google uses gRPC internally for billions of requests per day. It's built on HTTP/2 + Protocol Buffers, giving it 5–10× better performance than REST+JSON for internal service communication.

Why gRPC Wins Internally at FAANG

  • ⚡Protobuf serialization is 3–10× smaller than JSON — Binary format, no field name repetition. A 100KB JSON payload becomes 10KB protobuf.
  • ⚡HTTP/2 multiplexing — Multiple streams over one TCP connection. No head-of-line blocking.
  • 📋Strongly typed contracts (proto files) — Schema-first, code-generated clients in any language. No more "what does this field mean?"
  • 🔄Bi-directional streaming — Client streaming, server streaming, or full duplex. REST can't do this.
  • 🚫Poor browser support — Browsers can't use HTTP/2 trailers required by gRPC. Use gRPC-Web or REST for public APIs.
user-service.proto
1// 1. Define the contract in .proto file
2syntax = "proto3";
3
4package user;
5
6service UserService {
7 rpc GetUser (GetUserRequest) returns (UserResponse);
8 rpc ListUsers (ListUsersRequest) returns (stream UserResponse); // server streaming
stream keyword = server-side streaming. Client gets results as they arrive
9 rpc WatchUsers (stream UserFilter) returns (stream UserResponse); // bidirectional
Bidirectional streaming — both sides send and receive independently
10}
11
12message GetUserRequest {
13 string id = 1;
14}
15
16message UserResponse {
17 string id = 1;
18 string name = 2;
int64 for timestamps avoids timezone bugs. Proto3 has no Date type
19 string email = 3;
20 int64 created_at = 4; // epoch millis — no timezone ambiguity
21}
22
23// Generated TypeScript client (from protoc):
24// const client = new UserServiceClient('user-service:50051', credentials);
25// const user = await client.getUser({ id: '123' });
26// → Makes binary HTTP/2 call. No JSON parsing. ~10μs latency vs ~1ms REST.

The Decision Framework: Which One Do You Pick?

API Protocol Decision Tree

Is this a public-facing API?
YesUse REST (or GraphQL if UI teams need flexibility)
NoConsider gRPC for internal service communication
Do UI teams need flexible queries (different screens, different fields)?
YesUse GraphQL — Netflix, GitHub, Shopify all chose this
NoREST is simpler and well-understood
Is latency or throughput critical? (<1ms, >10k req/s)?
YesUse gRPC — Uber, Google, Square internal services
NoREST latency is acceptable for most use cases

The Netflix Pattern (and why it works)

Public API Gateway: REST. Internal services: gRPC. BFF (Backend for Frontend): GraphQL per product team. This is the pattern used at Netflix, Airbnb, and many large-scale companies. You don't have to pick one for everything.

CompanyPublic APIInternal ServicesReason
NetflixRESTgRPCREST for partners, gRPC for 600+ microservices
GitHubREST + GraphQL v4Internal RPCGraphQL lets API users fetch exactly what they need
StripeRESTInternal gRPCREST is easiest for payment integrations
GoogleREST (Cloud API)gRPC everywhereInvented gRPC for internal scale

War Story: The GraphQL Migration That Took 18 Months

A mid-size e-commerce company (10M monthly users) decided to "modernize" by migrating from REST to GraphQL. Timeline estimate: 6 months. Actual: 18 months.

What Went Wrong

  • 💥N+1 queries in production — Forgot DataLoader on the product-to-reviews resolver. 1 product page = 50 DB queries. Site crawled at 2× traffic.
  • 💥Caching broke completely — All GraphQL queries are POST requests. CDN caching stopped working. Had to implement Apollo persisted queries.
  • 💥Mobile clients broke on schema changes — GraphQL is "versionless" in theory. In practice, removing a field broke 6-month-old app versions still in use.
  • 💥Authorization was harder — In REST, you authorize by endpoint. In GraphQL, every field can expose different data — had to add field-level auth.

The Lesson

GraphQL solves real problems but adds new complexity. If your UI doesn't have extreme data fetching needs, REST is almost always the right choice. Don't migrate for modernization's sake.

How this might come up in interviews

Protocol questions test whether you understand real tradeoffs vs. hype. Don't say "GraphQL is better than REST" — that's a red flag. Say: "GraphQL solves X, REST solves Y, I'd choose based on..."

Common questions:

  • How would you decide between REST and GraphQL for a new product?
  • What is the N+1 problem and how do you solve it in GraphQL?
  • When would you choose gRPC over REST for internal services?
  • How do you version REST APIs without breaking existing clients?

Strong answers include:

  • Discusses tradeoffs in context of specific use cases
  • Mentions DataLoader unprompted when discussing GraphQL
  • Knows gRPC is binary and why that matters for performance

Red flags:

  • "GraphQL is always better than REST"
  • Doesn't know what HTTP status codes mean
  • Never heard of DataLoader or N+1 problem

Quick check · API Protocols: REST vs GraphQL vs gRPC

1 / 3

A mobile app team reports their home screen makes 5 API calls and receives too much unused data. Which protocol change would best address this?

Key takeaways

  • REST is the default: stateless, HTTP-native, universally understood. Use it unless you have a specific reason not to.
  • GraphQL solves over/under-fetching for complex UIs but adds schema management and N+1 complexity.
  • gRPC wins on performance for internal microservice communication — 5–10× faster than REST with HTTP/2 + protobuf.
  • The FAANG pattern: REST or GraphQL for public APIs, gRPC for internal services.
  • Changing protocols after clients are in production costs 6–18 months. Choose deliberately upfront.

From the books

Designing Web APIs — Brenda Jin, Saurabh Sahni, Amir Shevat (2018)

Chapter 3: API Paradigms

API design is a product decision, not just a technical one. Your protocol choice defines your developer experience.

Building Microservices — Sam Newman (2021)

Chapter 4: Communication Styles

Synchronous vs asynchronous matters more than which synchronous protocol you pick. Most teams jump to REST/gRPC without first asking if async would be better.

Ready to see how this works in the cloud?

Switch to Career Paths for structured paths (e.g. Developer, DevOps) and provider-specific lessons.

View role-based paths

Sign in to track your progress and mark lessons complete.

Discussion

Questions? Discuss in the community or start a thread below.

Join Discord

In-app Q&A

Sign in to start or join a thread.