Featured image of post REST vs. GraphQL vs. gRPC: The 'Restaurant Menu' Mental Model

REST vs. GraphQL vs. gRPC: The 'Restaurant Menu' Mental Model

Why does GraphQL exist if REST works fine? A mastery guide to API protocols, when to use each, and how gRPC changes the game for internal services.

“Should we use GraphQL?”

The engineering team splits in half. One side says it’s amazing. The other says REST is fine. Nobody can explain the difference without defaulting to “it depends.”

This guide settles it.

This is the Mastery Guide to API Protocols. We’ll use the “Restaurant Menu” model to understand REST (Fixed Menu), GraphQL (Custom Order), and gRPC (Walkie-Talkie between chefs).


Part 1: Foundations (The Mental Model)

REST = The Printed Menu

A REST API is like a restaurant with a printed menu. The kitchen decides what dishes exist. You pick from the list.

  • Strength: Simple, universal. Every language and every tool (Postman, curl) understands it.
  • Weakness: You get exactly what’s on the menu. If you only want the salad from the “Grilled Chicken Salad Combo,” you still pay for the whole combo. (Over-fetching). Or the menu doesn’t have exactly what you want; the waiter brings you three separate dishes. (Under-fetching).

GraphQL = The Custom Order

GraphQL is like a restaurant where you tell the chef exactly what you want.

  • “I want the chicken breast, no sauce, extra rice, and the mango salad dressing.”
  • The kitchen makes exactly that. One trip. Exactly what you asked for.
  • Strength: No over-fetching. No under-fetching. Perfect for mobile apps where bandwidth is limited.
  • Weakness: The kitchen is complex. You must manage a schema. Authorization is harder (is this user allowed to ask for user.creditCard?).

gRPC = The Chef’s Walkie-Talkie

gRPC is not for customers. It’s for kitchen-to-kitchen communication.

  • Chef from the Cold Kitchen radios Chef from the Hot Kitchen: “Steak ready?”
  • Uses a binary protocol (not human-readable text) for maximum speed.
  • Strongly typed. The contract is defined in a .proto file.
  • Strength: Blazing fast (3x-10x JSON/REST). Bi-directional streaming possible.
  • Weakness: Not for browsers. The .proto contract requires shared tooling.

Part 2: The Investigation (The Technical Differences)

1. The N+1 Problem (REST’s Achilles Heel)

Imagine a UI that shows a list of Posts with their Author names.

1
2
3
4
5
6
7
# 1 request for posts
GET /posts          → [{ id: 1, author_id: 5 }, { id: 2, author_id: 8 }, ...]

# Then N requests for each author!
GET /users/5        → { name: "Alice" }
GET /users/8        → { name: "Bob" }
... (For 50 posts → 51 total API calls)

GraphQL’s Fix: One query, exactly the data needed.

1
2
3
4
5
6
7
8
query {
  posts {
    title
    author {
      name  # GraphQL resolves this in ONE roundtrip
    }
  }
}

2. gRPC: The Proto Contract

The .proto file is the DNA of gRPC — a shared language both client and server understand.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// payment.proto
syntax = "proto3";

service PaymentService {
  rpc ProcessPayment (PaymentRequest) returns (PaymentResponse);
  rpc StreamUpdates (PaymentRequest) returns (stream PaymentEvent);  // Streaming!
}

message PaymentRequest {
  string order_id = 1;
  double amount = 2;
}

message PaymentResponse {
  bool success = 1;
  string transaction_id = 2;
}

From this one file, protoc generates strongly-typed client and server code for Python, Go, Java, etc.


Part 3: The Diagnosis (When to Use What)

Use CaseBest ChoiceWhy
Public API (third-party devs)RESTUniversal — any language, any tool.
Mobile App (bandwidth matters)GraphQLFetch exactly what the screen needs. No more.
Internal MicroservicesgRPCFast, type-safe, streaming support.
Real-time data (chat, live feed)GraphQL Subscriptions or gRPC StreamingBuilt-in streaming.
Simple CRUDRESTDon’t over-engineer.
BFF (Backend for Frontend)GraphQLAggregates multiple services for one UI.

Part 4: The Resolution (Code Examples)

1. REST (Python/Django)

1
2
3
4
5
6
7
8
# urls.py
path("posts/<int:pk>/", PostDetailView.as_view()),

# views.py
class PostDetailView(APIView):
    def get(self, request, pk):
        post = Post.objects.select_related("author").get(pk=pk)
        return Response(PostSerializer(post).data)

2. GraphQL (Python/Strawberry)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import strawberry
from typing import List

@strawberry.type
class Author:
    name: str

@strawberry.type
class Post:
    title: str
    author: Author

@strawberry.type
class Query:
    @strawberry.field
    def posts(self) -> List[Post]:
        return Post.objects.select_related("author").all()

schema = strawberry.Schema(query=Query)

3. gRPC (Python)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# server.py (Payment Service)
import grpc
import payment_pb2, payment_pb2_grpc

class PaymentServicer(payment_pb2_grpc.PaymentServiceServicer):
    def ProcessPayment(self, request, context):
        # request.order_id, request.amount are strongly typed!
        success = charge(request.amount)
        return payment_pb2.PaymentResponse(
            success=success,
            transaction_id="txn_123"
        )

# client.py (Order Service calling Payment Service)
channel = grpc.insecure_channel("payment-service:50051")
stub = payment_pb2_grpc.PaymentServiceStub(channel)
response = stub.ProcessPayment(
    payment_pb2.PaymentRequest(order_id="ord_456", amount=99.99)
)

Final Mental Model

1
2
3
4
5
6
7
REST     -> The Printed Menu. Universal, predictable, sometimes wasteful.
GraphQL  -> The Custom Order. Precise, powerful, complex to secure.
gRPC     -> The Chef's Walkie-Talkie. Fast, typed, internal only.

Over-fetching  -> "I asked for a user but got their entire order history too."
Under-fetching -> "I need author names, but /posts only gives me author_id."
N+1 Problem    -> "50 posts = 51 API calls." (GraphQL or SQL JOIN solves this)

Start with REST. Move to GraphQL only when mobile clients complain about data size. Move to gRPC when internal service latency becomes a bottleneck.

Made with laziness love 🦥

Subscribe to My Newsletter