REST vs GraphQL: Khi nào nên dùng? So sánh chi tiết cho Backend Developer
So sánh chi tiết REST API và GraphQL - Ưu nhược điểm, performance, use cases và hướng dẫn chọn đúng cho dự án của bạn.
Giới thiệu
REST hay GraphQL? Đây là decision phổ biến khi thiết kế API cho ứng dụng mới. Cả hai đều có ưu nhược điểm riêng, và không có winner tuyệt đối.
Bài viết này sẽ so sánh chi tiết từ góc độ Backend Developer - với các ví dụ thực tế và recommendations cụ thể.
Tổng quan nhanh
REST (Representational State Transfer)
- Kiến trúc dựa trên resources và HTTP methods
- Mỗi endpoint trả về fixed data structure
- Industry standard từ nhiều năm
GET /api/users/1 → Get user
POST /api/users → Create user
PUT /api/users/1 → Update user
DELETE /api/users/1 → Delete user
GraphQL
- Query language cho APIs
- Client quyết định data cần lấy
- Single endpoint, flexible queries
query {
user(id: 1) {
name
email
posts {
title
}
}
}
So sánh chi tiết
1. Data Fetching
REST: Fixed responses
// GET /api/users/1
{
"id": 1,
"name": "John",
"email": "john@example.com",
"address": { ... },
"preferences": { ... },
"createdAt": "2024-01-01"
}
Vấn đề: Over-fetching - client nhận data không cần.
GraphQL: Client specifies
query {
user(id: 1) {
name
email
}
}
Response chỉ chứa những gì request.
2. Multiple Resources
REST: Multiple requests
// Lấy user + posts + comments
const user = await fetch('/api/users/1');
const posts = await fetch('/api/users/1/posts');
const comments = await fetch('/api/posts/1/comments');
3 HTTP requests = Higher latency
GraphQL: Single request
query {
user(id: 1) {
name
posts {
title
comments {
text
author { name }
}
}
}
}
1 request = Lower latency
3. API Versioning
REST: Version trong URL
/api/v1/users
/api/v2/users → Breaking changes
Phải maintain multiple versions.
GraphQL: Deprecation thay vì versioning
type User {
name: String!
fullName: String! @deprecated(reason: "Use name instead")
}
Không cần versioning, evolve schema gradually.
4. Caching
REST: HTTP caching tự nhiên
GET /api/users/1
→ Cache-Control: max-age=3600
→ ETag: "abc123"
Browser và CDN có thể cache.
GraphQL: Caching phức tạp hơn
# Tất cả requests đều POST /graphql
# Không tận dụng được HTTP caching tự nhiên
Cần implement caching layer riêng (Apollo Client, Relay).
5. Error Handling
REST: HTTP status codes
// 200 OK, 404 Not Found, 500 Server Error
if (response.status === 404) {
// Handle not found
}
Clear, standardized.
GraphQL: Always 200, errors in response
{
"data": { "user": null },
"errors": [
{
"message": "User not found",
"extensions": { "code": "NOT_FOUND" }
}
]
}
Partial success possible, nhưng cần handle khác đi.
6. Type Safety
REST: OpenAPI/Swagger
# openapi.yaml
paths:
/users/{id}:
get:
responses:
200:
content:
application/json:
schema:
$ref: '#/components/schemas/User'
Generated docs, nhưng không enforce ở runtime.
GraphQL: Schema built-in
type Query {
user(id: ID!): User
}
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
Strong typing, validation automatic.
Performance Comparison
Request Overhead
| Scenario | REST | GraphQL |
|---|---|---|
| Get user profile | 1 request | 1 request |
| User + posts + comments | 3+ requests | 1 request |
| List with relations | N+1 risk | 1 request |
GraphQL wins cho complex data fetching.
Payload Size
| Scenario | REST | GraphQL |
|---|---|---|
| Fixed structure | Larger (over-fetch) | Exact (specify fields) |
| Simple CRUD | Optimal | Overhead (query syntax) |
Depends on use case.
Server Load
| Aspect | REST | GraphQL |
|---|---|---|
| Query parsing | None | Required |
| N+1 database | Easy to optimize | DataLoader needed |
| Caching | Easy | Complex |
REST simpler ở server side.
Implementation Examples
REST with Laravel
// routes/api.php
Route::apiResource('users', UserController::class);
Route::apiResource('users.posts', PostController::class);
// UserController.php
public function show(User $user)
{
return new UserResource(
$user->load(['posts', 'profile'])
);
}
GraphQL with Laravel
// graphql/schema.graphql
type Query {
user(id: ID! @eq): User @find
users: [User!]! @paginate
}
type User {
id: ID!
name: String!
posts: [Post!]! @hasMany
}
// Resolvers automatic với Lighthouse PHP
Khi nào chọn REST?
✅ Use REST when:
-
Simple CRUD operations
- Blog, CMS, e-commerce basics
- Well-defined resources
-
Caching critical
- Public APIs
- CDN-heavy applications
-
Team không familiar GraphQL
- Learning curve exists
- REST is universal knowledge
-
Third-party integration
- Partners expect REST
- Webhooks, callbacks
-
File uploads
- Native support
- GraphQL cần workarounds
Example: Blog API
GET /posts → List posts
GET /posts/{id} → Get post
POST /posts → Create post
PUT /posts/{id} → Update post
DELETE /posts/{id} → Delete post
Simple, clear, cacheable.
Khi nào chọn GraphQL?
✅ Use GraphQL when:
-
Complex, nested data
- Social networks
- Dashboard với nhiều widgets
-
Multiple clients với needs khác nhau
- Mobile app cần ít data
- Web app cần nhiều data
-
Rapid iteration
- Frontend team tự serve
- Không cần API changes
-
Real-time features
- Subscriptions built-in
- Live updates
-
Microservices aggregation
- API Gateway pattern
- Federated GraphQL
Example: Social Feed
query {
feed {
posts {
id
content
author {
name
avatar
}
likes { count }
comments(first: 3) {
text
author { name }
}
}
}
}
Single request replaces 5+ REST calls.
Hybrid Approach
Không nhất thiết phải chọn một:
Public API: REST (cacheable, documented)
Mobile App: GraphQL (flexible, efficient)
Internal: REST (simple CRUD)
Dashboard: GraphQL (complex queries)
Decision Framework
┌─────────────────────────────────────┐
│ Data fetching phức tạp? │
│ (nested, multiple resources) │
└────────────┬────────────────────────┘
│
┌──────┴──────┐
│ │
YES NO
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│ GraphQL │ │ REST │
└─────────┘ └─────────┘
Thêm considerations:
- Caching critical? → REST
- Real-time? → GraphQL (subscriptions)
- Team expertise? → Dùng cái team biết
- Third-party integration? → REST
Common Mistakes
❌ GraphQL cho Simple CRUD
# Over-engineering
mutation {
createUser(input: { name: "John", email: "john@test.com" }) {
id
name
}
}
REST đơn giản hơn cho case này.
❌ REST cho Complex Dashboard
// Dashboard cần 10 API calls
await Promise.all([
fetch('/api/users/stats'),
fetch('/api/orders/recent'),
fetch('/api/revenue/monthly'),
// ...7 more
]);
GraphQL sẽ efficient hơn nhiều.
❌ Không dùng DataLoader với GraphQL
// N+1 query problem
// 100 posts → 100 queries for authors
Luôn implement DataLoader cho relationships.
Kết luận
| Criteria | Winner |
|---|---|
| Simple CRUD | REST |
| Complex queries | GraphQL |
| Caching | REST |
| Type safety | GraphQL |
| Learning curve | REST |
| Flexibility | GraphQL |
| Tooling | Tie |
Final Recommendations:
Choose REST if:
- Team mới với API development
- Simple, cacheable resources
- Third-party integration needs
Choose GraphQL if:
- Complex data requirements
- Multiple clients (web, mobile, etc.)
- Need rapid frontend iteration
Pro tip: Bắt đầu với REST cho MVP, migrate sang GraphQL khi complexity tăng. Migration không khó nếu có clear data layer.
Thử Thách Kiến Thức Lịch Sử?
Khám phá hàng trăm câu hỏi trắc nghiệm lịch sử thú vị tại HistoQuiz. Vừa học vừa chơi, nâng cao kiến thức ngay hôm nay!