REST vs. GraphQL vs. gRPC: Mô hình tư duy 'Thực đơn Nhà hàng'
Tại sao GraphQL lại ra đời nếu REST đã ổn? Hướng dẫn chuyên sâu về giao thức API, khi nào dùng cái nào, và tại sao gRPC thay đổi cuộc chơi cho các service nội bộ.
“Chúng ta có nên dùng GraphQL không?”
Team chia đôi ngay lập tức. Một nửa bảo xịn lắm. Nửa kia bảo REST thế là ổn rồi. Không ai giải thích được sự khác biệt mà không phải dùng đến câu “it depends.”
Bài viết này giải quyết dứt điểm.
Đây là Hướng dẫn chuyên sâu về Giao thức API. Chúng ta sẽ dùng mô hình “Thực đơn Nhà hàng” để hiểu REST (Thực đơn in sẵn), GraphQL (Gọi món tùy ý) và gRPC (Bộ đàm giữa các đầu bếp).
Phần 1: Nền tảng (Mô hình tư duy)
REST = Thực đơn In sẵn
REST API giống như nhà hàng có thực đơn in sẵn. Bếp quyết định có những món gì. Bạn chọn từ danh sách đó.
- Điểm mạnh: Đơn giản, phổ quát. Mọi ngôn ngữ, mọi công cụ (Postman, curl) đều hiểu.
- Điểm yếu: Bạn nhận đúng cái có trên thực đơn. Nếu chỉ muốn cái salad trong “Combo Gà Nướng + Salad,” bạn vẫn phải trả tiền cả combo. (Over-fetching). Hoặc thực đơn không có đúng thứ bạn cần; bồi bàn phải mang ba món riêng ra. (Under-fetching).
GraphQL = Gọi món Tùy ý
GraphQL giống như nhà hàng nơi bạn nói chính xác với đầu bếp những gì bạn muốn.
- “Cho tôi ức gà không nước sốt, thêm cơm, và sốt salad xoài.”
- Bếp làm đúng cái đó. Một chuyến bưng. Đúng những gì bạn yêu cầu.
- Điểm mạnh: Không over-fetching. Không under-fetching. Cực tốt cho mobile app nơi băng thông có hạn.
- Điểm yếu: Bếp phức tạp hơn. Phải quản lý schema. Phân quyền khó hơn (user này có được hỏi
user.creditCardkhông?).
gRPC = Bộ đàm giữa các đầu bếp
gRPC không dành cho khách hàng. Nó dành cho giao tiếp bếp-với-bếp.
- Đầu bếp Bộ phận Đồ lạnh gọi bộ đàm cho Bộ phận Đồ nóng: “Bít tết xong chưa?”
- Dùng giao thức nhị phân (không phải text có thể đọc được) để tối đa tốc độ.
- Strongly typed. Hợp đồng được định nghĩa trong file
.proto. - Điểm mạnh: Nhanh gấp bội (3x-10x JSON/REST). Hỗ trợ streaming hai chiều.
- Điểm yếu: Không dùng được trên browser. File
.protocần tooling chung.
Phần 2: Điều tra (Khác biệt kỹ thuật)
1. Vấn đề N+1 (Gót chân Achilles của REST)
Một UI hiển thị danh sách bài viết (Posts) kèm tên tác giả.
# 1 request cho danh sách bài viết
GET /posts → [{ id: 1, author_id: 5 }, { id: 2, author_id: 8 }, ...]
# Rồi N request cho từng tác giả!
GET /users/5 → { name: "Alice" }
GET /users/8 → { name: "Bob" }
... (50 bài viết → 51 lần gọi API)
GraphQL giải quyết: Một query, lấy đúng dữ liệu cần.
query {
posts {
title
author {
name # GraphQL giải quyết trong MỘT lần gọi
}
}
}
2. gRPC: Hợp đồng Proto
File .proto là ADN của gRPC — ngôn ngữ chung mà cả client lẫn server đều hiểu.
// 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;
}
Từ một file này, protoc tự sinh ra code client và server strongly-typed cho Python, Go, Java,…
Phần 3: Chẩn đoán (Khi nào dùng gì?)
| Use Case | Lựa chọn tốt nhất | Tại sao |
|---|---|---|
| API Công khai (dev bên thứ ba) | REST | Phổ quát — ngôn ngữ nào cũng dùng được. |
| Mobile App (băng thông quan trọng) | GraphQL | Lấy đúng dữ liệu màn hình cần, không hơn không kém. |
| Microservice Nội bộ | gRPC | Nhanh, type-safe, hỗ trợ streaming. |
| Dữ liệu Realtime (chat, feed) | GraphQL Subscriptions hoặc gRPC Streaming | Streaming được tích hợp sẵn. |
| CRUD đơn giản | REST | Đừng phức tạp hóa không cần thiết. |
| BFF (Backend for Frontend) | GraphQL | Tổng hợp nhiều service cho một UI. |
Phần 4: Giải pháp (Code Examples)
1. REST (Python/Django)
# 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)
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)
# server.py (Payment Service)
class PaymentServicer(payment_pb2_grpc.PaymentServiceServicer):
def ProcessPayment(self, request, context):
# request.order_id, request.amount là strongly typed!
success = charge(request.amount)
return payment_pb2.PaymentResponse(
success=success,
transaction_id="txn_123"
)
# client.py (Order Service gọi 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)
)
Mô hình tư duy chốt hạ
REST -> Thực đơn in sẵn. Phổ quát, dễ đoán, đôi khi lãng phí.
GraphQL -> Gọi món tùy ý. Chính xác, mạnh, phức tạp để phân quyền.
gRPC -> Bộ đàm đầu bếp. Nhanh, typed, chỉ dùng nội bộ.
Over-fetching -> "Tôi hỏi thông tin user nhưng nhận về cả lịch sử đơn hàng."
Under-fetching -> "Cần tên tác giả, nhưng /posts chỉ cho author_id."
N+1 Problem -> "50 bài = 51 lần gọi API." (GraphQL hoặc SQL JOIN giải quyết được)
Bắt đầu với REST. Chuyển sang GraphQL chỉ khi client mobile than phiền về lượng data. Chuyển sang gRPC khi latency của service nội bộ trở thành nút cổ chai.
Bài viết liên quan
-
Rate Limiting & Circuit Breaker: Mô hình tư duy 'Đèn Giao thông & Hộp Cầu dao'
Làm sao ngăn một client xấu làm sập toàn bộ API của bạn? Hướng dẫn chuyên sâu về chiến lược rate limiting, circuit breaker và các pattern tăng cường độ bền.
-
Chứng chỉ API & Chuỗi niềm tin (Chain of Trust): Mô hình tư duy chuẩn chỉ
Dừng việc đoán mò với lỗi SSL. Hướng dẫn cấp độ chuyên gia về Chain of Trust, debug bằng openssl và cách chứng minh lỗi thuộc về ai.
-
Authentication vs. Authorization vs. OAuth: Mô hình tư duy 'Thẻ Căn cước'
Đừng nhầm lẫn 401 và 403 nữa. Hướng dẫn chuyên sâu về AuthN (Bạn là ai), AuthZ (Bạn được làm gì) và OAuth (Chìa khóa Valet).
-
Caching & Redis: Mô hình tư duy 'Tờ giấy nhớ'
Tại sao Redis làm mọi thứ nhanh hơn? Hướng dẫn chuyên sâu về cache invalidation (vấn đề khó nhất CS), các chiến lược eviction, và Redis data types.