Content to action
Qubicweb keeps the discovery and trust-education layer lightweight. When you need governed account, commerce, service, or trust actions, continue in the canonical app without losing the article’s source context.
Content to action
Qubicweb keeps the discovery and trust-education layer lightweight. When you need governed account, commerce, service, or trust actions, continue in the canonical app without losing the article’s source context.
Brief points
Key points will appear here once TrustOps condenses this read. Use the source link below if you need the full article immediately.
GraphQL là ngôn ngữ truy vấn cho API, do Facebook phát triển năm 2015. Thay vì server quyết định bạn nhận được gì, client tự chỉ định chính xác dữ liệu mình cần.
| REST | GraphQL | |
|---|---|---|
| Endpoint | Nhiều (/users, /posts...) |
Chỉ 1 (/graphql) |
| Dữ liệu trả về | Fixed, server quyết định | Linh hoạt, client quyết định |
| Over-fetching | Thường xuyên | Không bao giờ |
| Under-fetching | Phải gọi nhiều request | Lấy 1 lần được hết |
Feed social cần render cùng lúc: avatar, tên user, ảnh post, số like, top comment...
REST: 4–5 request tuần tự hoặc song song
GET /feed
GET /users/:id
GET /posts/:id/likes
GET /posts/:id/comments
GraphQL: 1 request duy nhất, server tự resolve
queryFeed{feed{author{avatarnameisFollowing}contentimageslikes{countisLikedByMe}topComments{textauthor{name}}}}
→ Giảm latency, giảm round-trip, render nhanh hơn rõ rệt.
Màn hình khác nhau → nhu cầu data khác nhau:
| Màn hình | Cần gì |
|---|---|
| Feed (thumbnail) |
name, avatar, title, likeCount
|
| Post detail | thêm fullContent, comments, shares
|
| Profile card | chỉ name, avatar, followerCount
|
REST trả về cùng 1 response nặng cho tất cả. GraphQL cho phép mỗi screen query đúng field nó cần — đặc biệt quan trọng với mobile, tiết kiệm bandwidth đáng kể.
REST — FE phải tự join và normalize:
const user = await getUser(id)
const posts = await getPosts(id)
const followers = await getFollowers(id) // Rồi tự map, merge...
const profileData = mergeAndNormalize(user, posts, followers)
GraphQL — server chịu trách nhiệm resolve mọi relationship, FE nhận về 1 object sẵn sàng dùng. Logic mapping nằm ở tầng resolver thay vì rải rác ở từng màn hình.
Social feed hay có pattern: cùng 1 user xuất hiện ở nhiều post.
DataLoader pattern tự động batch + deduplicate:
Post 1 → author_id: 42 ┐
Post 2 → author_id: 17 ├─ DataLoader → 1 DB query duy nhất
Post 3 → author_id: 42 ┘ SELECT * FROM users WHERE id IN (42, 17)
Client-side (Apollo/urql) cũng normalize cache theo object ID — user cập nhật avatar ở 1 chỗ, toàn bộ feed tự cập nhật, không cần refetch.
GraphQL có Introspection tích hợp sẵn: schema chính là documentation. Công cụ như GraphiQL / Apollo Sandbox cho phép:
→ FE và BE làm việc từ cùng 1 source of truth — schema file. Thêm field mới, FE thấy ngay.
/api/auth/me
Đây là ví dụ điển hình về vấn đề REST gặp phải trong production.
//GET/api/auth/me{"id":123456,"name":"Nguyễn Văn A","avatar":"https://...","coin":45200,"rank":"GOLD",//❌aggregateloyalty_histories"rankProgress":78.5,//❌tínhtoánnặng"totalEarned":1250000,//❌SUMtoànbộlịchsử"totalSpent":890000,//❌SUMtoànbộlịchsử"referralCount":12,//❌COUNTtừbảngreferrals"taskCompletedCount":47,//❌COUNTtừbảngtask_points"badges":[...]//❌JOINthêmbảngbadges}
Mỗi lần app load → gọi /auth/me → server tính toán tất cả, dù màn hình chỉ cần hiện tên + avatar.
| Field | Chi phí server | Tần suất FE dùng |
|---|---|---|
name, avatar, coin
|
Rất thấp | Mọi màn hình |
rank, rankProgress
|
Nặng — aggregate loyalty_histories
|
Chỉ màn hình Profile/Rank |
totalEarned, totalSpent
|
Nặng — SUM toàn lịch sử | Chỉ màn hình Thống kê |
referralCount |
Trung bình | Chỉ màn hình Referral |
taskCompletedCount |
Trung bình | Chỉ màn hình Task |
badges |
Nặng — multi JOIN | Chỉ màn hình Profile |
→ 90% request /auth/me chỉ cần 3–4 field đầu, nhưng vẫn phải trả tiền tính toán toàn bộ.
App header (render mọi lúc):
queryAppHeader{me{nameavatarcoin# query cực nhẹ, chỉ SELECT 3 fields}}
Màn hình Profile/Rank (user chủ động vào):
queryProfileScreen{me{nameavatarcoinrank# chỉ tính khi user thực sự mở màn hình nàyrankProgressbadges}}
Màn hình Thống kê (vào ít nhất):
queryStatsScreen{me{totalEarned# heavy computation chỉ chạy khi cầntotalSpentreferralCounttaskCompletedCount}}
| REST hiện tại | GraphQL | |
|---|---|---|
| App header load | ~150ms (tính toán full) | ~8ms (chỉ SELECT 3 fields) |
| Profile/Rank | ~150ms (dù không cần) | ~120ms (lazy, chỉ khi vào) |
| Server load (600K users) | Tính rank cho tất cả | Chỉ tính khi được query |
Heavy field như rank trở thành lazy resolver — không tốn tài nguyên tính toán cho 600K user mỗi khi họ mở app.
Spot something off?