Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Bài 8 — GraphQL vs REST — Khi nào dùng cái nào

Technical Product Manager Bài 8/60

Mở đầu — vì sao bài này quan trọng

Bạn vừa nắm vững nguyên tắc thiết kế REST API ở bài trước. Nhưng nếu bạn ngồi họp với team kỹ thuật, sớm muộn sẽ có một engineer giơ tay đề xuất: "Sao mình không dùng GraphQL cho cái này?". Lúc đó, nếu PM chỉ biết gật gù hoặc lắc đầu theo cảm tính, bạn đã đánh mất một cơ hội quan trọng để tham gia vào quyết định kiến trúc — quyết định sẽ ảnh hưởng đến tốc độ phát triển, trải nghiệm người dùng, và chi phí vận hành trong nhiều năm.

GraphQL không phải là "REST phiên bản mới hơn, tốt hơn". Đây là hai triết lý thiết kế khác nhau, mỗi cái mạnh ở một bối cảnh. Một Technical PM giỏi không phải người chọn theo trend, mà là người hiểu được trade-off để chọn đúng công cụ cho đúng bài toán. Quan trọng hơn, bạn cần hiểu đủ sâu để đặt câu hỏi chất lượng cho team, ước lượng được rủi ro, và giải thích lựa chọn đó cho cả lãnh đạo lẫn các stakeholder không rành kỹ thuật.

Bài này không biến bạn thành người viết schema GraphQL. Mục tiêu là cho bạn một khung tư duy ra quyết định: khi nào REST là lựa chọn an toàn và đúng đắn, khi nào GraphQL thực sự giải quyết được nỗi đau, và những cái giá ẩn mà ít ai nói cho bạn nghe.

Khái niệm cốt lõi

REST ngắn gọn — và hai vấn đề kinh điển

REST tổ chức API quanh các "tài nguyên" (resource), mỗi tài nguyên có một endpoint riêng. Ví dụ GET /users/42 trả về thông tin user số 42, GET /users/42/orders trả về đơn hàng của user đó. Mỗi endpoint trả về một cấu trúc dữ liệu cố định (fixed shape) — server quyết định bạn nhận được những field nào.

Chính sự cố định này sinh ra hai vấn đề kinh điển mà GraphQL ra đời để giải quyết:

Over-fetching (lấy thừa): Bạn chỉ cần hiển thị tên và avatar của user trên màn hình danh sách bình luận. Nhưng endpoint GET /users/42 trả về cả ngày sinh, địa chỉ, số điện thoại, lịch sử đăng nhập... — hàng chục field bạn không dùng. Với một bình luận thì không sao, nhưng với màn hình hiển thị 50 bình luận, bạn đang tải về lượng dữ liệu gấp nhiều lần nhu cầu thực. Trên kết nối 3G ở vùng nông thôn Việt Nam, điều này nghĩa là màn hình tải chậm hơn đáng kể.

Under-fetching (lấy thiếu): Để dựng màn hình profile, bạn cần thông tin user, 5 đơn hàng gần nhất, và danh sách sản phẩm trong wishlist. Với REST, đó là ba lần gọi API riêng biệt: /users/42, /users/42/orders?limit=5, /users/42/wishlist. Ba round-trip mạng, mỗi cái có độ trễ riêng. Trên mobile, ba lần gọi nối tiếp nhau có thể khiến màn hình "giật" khi dữ liệu nhảy vào từng phần.

GraphQL — client tự khai báo cái mình cần

GraphQL đảo ngược quyền kiểm soát. Thay vì server quyết định trả về gì, client tự khai báo chính xác dữ liệu mình cần trong một truy vấn (query) duy nhất, gửi đến một endpoint duy nhất (thường là /graphql).

Hãy hình dung query này:

query {
  user(id: 42) {
    name
    avatar
    orders(last: 5) { id, total, status }
    wishlist { productName, price }
  }
}

Server đọc query, trả về đúng cấu trúc đó — không thừa một field, không thiếu một mối quan hệ. Một request, đúng dữ liệu cần, giải quyết cả over-fetching lẫn under-fetching trong một lần.

Vài khái niệm cốt lõi PM cần nắm:

  • Schema: Bản hợp đồng định nghĩa toàn bộ kiểu dữ liệu và quan hệ giữa chúng. Đây là "nguồn sự thật" mà cả frontend và backend cùng nhìn vào — một lợi thế lớn cho việc phối hợp.
  • Query / Mutation: Query để đọc dữ liệu, Mutation để thay đổi dữ liệu (tạo, sửa, xóa). Tương ứng với GET và POST/PUT/DELETE bên REST.
  • Resolver: Đoạn code backend chịu trách nhiệm "trả lời" từng field trong query. Đây là nơi chứa rủi ro hiệu năng mà ta sẽ bàn ở phần lỗi thường gặp.

Sự khác biệt không nằm ở "cái nào tốt hơn"

Điểm mấu chốt PM phải khắc cốt: GraphQL đẩy độ phức tạp từ phía client sang phía server. REST đơn giản ở server (mỗi endpoint là một hàm rõ ràng) nhưng đẩy gánh nặng ghép nối dữ liệu cho client. GraphQL làm client nhẹ nhàng nhưng đòi hỏi tầng server phức tạp hơn, khó cache hơn, khó giám sát hơn. Bạn không loại bỏ được độ phức tạp — bạn chỉ chọn nơi để nó tồn tại.

Bảng so sánh nhanh để PM ghi nhớ

  • Caching: REST tận dụng được cache HTTP của trình duyệt và CDN gần như miễn phí (mỗi URL là một khóa cache tự nhiên). GraphQL gửi mọi thứ qua một URL với method POST, nên cache tầng HTTP gần như vô dụng — phải tự xây cache phức tạp hơn.
  • Phiên bản (versioning): REST thường dùng /v1, /v2. GraphQL khuyến khích tiến hóa schema liên tục, thêm field mới và đánh dấu field cũ là deprecated thay vì nhảy version.
  • Đường cong học tập: REST quen thuộc với hầu như mọi developer. GraphQL cần thời gian để team làm quen, đặc biệt là phần tối ưu resolver.
  • Công cụ giám sát: Hệ sinh thái giám sát REST đã trưởng thành. GraphQL cần công cụ chuyên biệt vì mọi request đều trông giống nhau từ bên ngoài.

Tình huống thực tế

Tình huống 1 — Sàn TMĐT chuyển sang GraphQL để cứu app mobile

Hãy lấy bối cảnh một sàn thương mại điện tử cỡ trung ở Việt Nam, gọi là "ChợViệt". App mobile của họ có màn hình trang chủ phức tạp: banner khuyến mãi, danh mục, sản phẩm gợi ý cá nhân hóa, flash sale đang chạy, và giỏ hàng của user. Với kiến trúc REST cũ, mỗi lần mở app, client phải gọi 7 endpoint khác nhau.

Đội data đo được: thời gian từ lúc mở app đến lúc trang chủ hiển thị đầy đủ trung bình 3,8 giây trên mạng 4G yếu — và tệ hơn nhiều ở các tỉnh. Tỷ lệ thoát app trong 5 giây đầu lên tới 22%.

Team quyết định đưa vào một tầng GraphQL. Toàn bộ trang chủ giờ chỉ cần một query duy nhất, server tự ghép dữ liệu từ các microservice nội bộ. Kết quả sau ba tháng: thời gian hiển thị trang chủ giảm còn 2,1 giây, tỷ lệ thoát giảm xuống 14%. Lý do then chốt không chỉ là gộp request, mà còn vì mỗi màn hình lấy đúng field cần — màn hình danh sách lấy ít field, màn hình chi tiết lấy nhiều — thay vì dùng chung một response REST nặng nề.

Bài học: GraphQL tỏa sáng khi bạn có client phong phú (mobile, web) với nhu cầu dữ liệu đa dạng, và độ trễ mạng là nỗi đau thực sự. Quyết định dựa trên con số đo được, không phải cảm tính.

Tình huống 2 — Một startup fintech chọn REST và đã đúng

Ngược lại, hãy xét một startup fintech, gọi là "PayNhanh", xây API thanh toán cho các merchant tích hợp. Một bạn engineer mới về, vừa đọc xong bài blog tâng bốc GraphQL, đề xuất chuyển toàn bộ public API sang GraphQL cho "hiện đại".

PM ngồi lại và đặt vài câu hỏi sắc bén. Ai là người tiêu thụ API này? — Là các merchant bên ngoài, đa phần là developer của các cửa hàng nhỏ, kỹ năng kỹ thuật không đồng đều. Họ cần gì? — Sự đơn giản, tài liệu rõ ràng, và khả năng debug dễ dàng khi giao dịch lỗi. Có cần linh hoạt chọn field không? — Không, một giao dịch thanh toán có cấu trúc cố định, ai cũng cần gần như cùng một bộ field.

Quan trọng hơn, với API thanh toán, khả năng giám sát từng endpoint, đặt rate limit theo từng thao tác, và cache thông tin tỷ giá là tối quan trọng — tất cả đều dễ với REST và rắc rối với GraphQL. PM kết luận: giữ REST. Cái giá của GraphQL ở đây (độ phức tạp giám sát, khó cache, đường cong học tập cho merchant) lớn hơn nhiều so với lợi ích linh hoạt mà chẳng ai cần.

Bài học: Với public API cho đối tác bên ngoài có cấu trúc dữ liệu ổn định, REST thường là lựa chọn đúng. PM giỏi là người dám nói "không" với công nghệ thời thượng khi nó không giải quyết vấn đề thực.

Tình huống 3 — Mô hình lai (hybrid) tại một super-app

Một super-app khu vực Đông Nam Á (kiểu Grab hay Gojek) thường không chọn một bên. Họ dùng GraphQL cho tầng API mà các app khách hàng và tài xế gọi đến — gọi là tầng BFF (Backend For Frontend) — nơi nhu cầu dữ liệu đa dạng và thay đổi liên tục theo từng phiên bản app. Nhưng bên dưới, giao tiếp giữa hàng trăm microservice nội bộ vẫn dùng REST (hoặc gRPC) vì sự đơn giản, dễ giám sát và hiệu năng.

Cách bố trí này tách bạch hai mối quan tâm: GraphQL phục vụ trải nghiệm client linh hoạt ở rìa hệ thống, còn REST giữ cho lõi hệ thống nội bộ gọn gàng, dễ vận hành.

Bài học: Quyết định không nhất thiết là "chọn một". Là PM, bạn nên hỏi team: "Mình dùng cái nào ở tầng nào?" thay vì ép cả hệ thống theo một chuẩn duy nhất.

Hướng dẫn từng bước

Khi bạn đứng trước một quyết định GraphQL hay REST, đây là quy trình PM nên dẫn dắt:

Bước 1 — Xác định người tiêu thụ API. API này phục vụ ai? Client nội bộ của chính team (app mobile, web của bạn) hay đối tác bên ngoài? Một client hay nhiều loại client với nhu cầu khác nhau? Client nội bộ đa dạng nghiêng về GraphQL; đối tác bên ngoài nghiêng về REST.

Bước 2 — Đo lường nỗi đau thực tế. Đừng quyết định trên giả định. Có thật sự đang over-fetching không? Có bao nhiêu round-trip cho một màn hình quan trọng? Độ trễ mạng có phải vấn đề với người dùng của bạn không? Yêu cầu team đưa ra con số: số request mỗi màn hình, dung lượng response, thời gian tải.

Bước 3 — Đánh giá độ ổn định của cấu trúc dữ liệu. Nếu các màn hình cần những tổ hợp dữ liệu rất khác nhau và thay đổi liên tục, GraphQL giúp bạn không phải sửa server mỗi lần frontend đổi nhu cầu. Nếu dữ liệu có hình dạng cố định, lợi thế này biến mất.

Bước 4 — Tính cái giá vận hành. Hỏi thẳng team: Mình có kinh nghiệm vận hành GraphQL chưa? Ai sẽ lo về caching, về vấn đề N+1 query, về rate limiting? Nếu team chưa từng làm và không có thời gian học, rủi ro kỹ thuật là có thật.

Bước 5 — Cân nhắc phương án lai. Hỏi liệu có thể dùng GraphQL ở tầng BFF cho client còn giữ REST ở lõi không. Thường đây là câu trả lời thực tế nhất.

Bước 6 — Ra quyết định và ghi lại lý do. Viết một đoạn ngắn (trong Technical Spec hoặc một quyết định kiến trúc) nêu rõ: chọn gì, vì sao, và đánh đổi gì. Sáu tháng sau khi có người hỏi lại, tài liệu này cứu bạn.

Lỗi thường gặp & mẹo

Lỗi 1 — Tưởng GraphQL "nhanh hơn REST". Sai. GraphQL không tự động nhanh hơn. Nó giảm số round-trip và giảm over-fetching, nhưng một query phức tạp viết kém có thể chậm hơn nhiều endpoint REST gọn gàng. Tốc độ phụ thuộc vào cách viết resolver, không phải vào nhãn công nghệ.

Lỗi 2 — Bỏ qua vấn đề N+1. Đây là cái bẫy hiệu năng kinh điển của GraphQL. Khi client query danh sách 100 sản phẩm và mỗi sản phẩm hỏi thông tin người bán, một backend ngây thơ sẽ chạy 1 query lấy sản phẩm rồi 100 query lấy người bán — tổng 101 query, làm sập database. PM nên hỏi team: "Mình đã xử lý N+1 chưa? Có dùng DataLoader hay cơ chế gom batch không?". Câu hỏi này cho thấy bạn hiểu vấn đề.

Lỗi 3 — Quên rủi ro query phức tạp tùy ý. Vì client tự viết query, một query lồng sâu độc hại (cố ý hoặc vô tình) có thể buộc server làm việc khổng lồ. REST không có vấn đề này vì mỗi endpoint giới hạn sẵn. Với GraphQL public, team cần đặt giới hạn độ sâu query và phân tích chi phí query.

Lỗi 4 — Đánh giá thấp việc mất cache HTTP. Nhiều team chuyển sang GraphQL rồi mới phát hiện mất sạch khả năng cache ở tầng CDN mà REST cho không. Hệ quả là tải lên database tăng vọt. Hãy hỏi về chiến lược cache ngay từ đầu.

Mẹo cho PM: Khi tranh luận, kéo cuộc thảo luận khỏi câu hỏi "công nghệ nào ngầu hơn" và hướng về "người dùng và đối tác của chúng ta cần gì, và cái giá vận hành chúng ta gánh nổi là bao nhiêu". Đó là vai trò của bạn.

Bài tập thực hành

  • Phân tích over-fetching: Mở một app bạn hay dùng (ví dụ một sàn TMĐT Việt Nam), bật công cụ Network trong trình duyệt, và quan sát một màn hình. Đếm xem có bao nhiêu request được gọi, và thử đoán xem màn hình đó có thể hưởng lợi từ GraphQL không. Viết 5 dòng kết luận.
  • Đóng vai ra quyết định: Giả sử bạn là PM của một nền tảng đặt lịch khám bệnh. Một bên là app bệnh nhân (giao diện phong phú, nhiều màn hình khác nhau), một bên là API cho các phòng khám đối tác tích hợp. Với mỗi bên, bạn chọn GraphQL hay REST? Viết lý do cho từng lựa chọn theo 6 bước ở phần Hướng dẫn.
  • Soạn câu hỏi cho team: Viết ra 5 câu hỏi kỹ thuật bạn sẽ đặt cho engineer khi họ đề xuất chuyển một API sang GraphQL. Ít nhất phải có câu về N+1, về caching, và về rate limiting.

Tóm tắt

GraphQL và REST không phải cuộc đua xem ai thắng — đây là hai công cụ với điểm mạnh khác nhau. REST đơn giản, dễ cache, dễ giám sát, là lựa chọn an toàn cho public API và giao tiếp nội bộ với dữ liệu ổn định. GraphQL trao quyền cho client tự chọn dữ liệu, giải quyết over-fetching và under-fetching, tỏa sáng khi bạn có nhiều loại client với nhu cầu đa dạng và độ trễ mạng là nỗi đau thực sự — nhưng đổi lại là độ phức tạp ở server, mất cache HTTP, và những bẫy hiệu năng như N+1.

Là Technical PM, giá trị của bạn không nằm ở việc viết query GraphQL, mà ở việc dẫn dắt quyết định: xác định người dùng API, đo lường nỗi đau thực tế, tính cái giá vận hành, cân nhắc phương án lai, và ghi lại lý do. Hãy nhớ tình huống PayNhanh — đôi khi quyết định dũng cảm nhất là nói "không" với công nghệ thời thượng. Và hãy nhớ ChợViệt — đôi khi con số đo được sẽ chỉ thẳng cho bạn câu trả lời. Chọn đúng công cụ cho đúng bài toán, đó mới là kỹ năng cốt lõi.