Nguyen Le PhongNguyen Le Phong

GraphQL và REST

Một bài so sánh thực tế giữa GraphQL và REST: mỗi cách định hình API contract, độ linh hoạt cho frontend, caching, observability, ownership trong team và trade-off vận hành khi chọn một phong cách API.

Lần đầu GraphQL làm tôi thấy hấp dẫn không phải trong một buổi họp architecture. Đó là lúc sửa một UI nhỏ, kiểu ticket nhìn qua tưởng rất nhẹ. Một card cần thêm một field, rồi thêm một count lồng bên trong, rồi thêm một status label lấy từ service khác. Frontend đã sẵn sàng, design đã rõ, nhưng REST response lại được thiết kế cho màn hình của ngày hôm qua. Một người mở API contract, một người hỏi có nên thêm endpoint mới không, và chiếc card nhỏ biến thành cuộc nói chuyện về ownership.

Cuộc tranh luận GraphQL và REST trong đời thật thường bắt đầu như vậy. Nó không bắt đầu bằng một bảng so sánh hoàn hảo. Nó bắt đầu khi một phía của hệ thống cần dữ liệu theo hình dạng mà phía kia chưa đoán trước. REST nói, theo một cách rất hữu ích, rằng resource quan trọng. Product, order, user, comment: mỗi thứ có URL ổn định, method rõ, cách cache quen thuộc và mental model nhiều engineer hiểu nhanh. GraphQL nói, theo một cách khác cũng hữu ích, rằng client thường biết chính xác câu hỏi dữ liệu của nó hơn server có thể đoán trước.

REST thường dễ bắt đầu hơn vì boundary của nó nhìn thấy được. Bạn nhìn vào một endpoint và hiểu nó đại diện cho điều gì. HTTP caching, status code, log, rate limit và browser tooling đều đi cùng khá tự nhiên. Với nhiều product, điều này đủ dùng trong một thời gian dài. Một team nhỏ, vài client, resource model rõ và màn hình tương đối ổn định có thể đi rất tốt với REST. Sự đơn giản đó không phải thiếu tinh tế. Nó là một lý do REST sống qua rất nhiều chu kỳ công nghệ.

GraphQL trở nên thú vị khi bề mặt product phát triển nhanh hơn hình dạng endpoint cũ. Mobile cần ít field hơn vì bandwidth quan trọng. Web cần nhiều dữ liệu liên quan hơn vì page dày. Một dashboard muốn kết hợp object từ nhiều domain. Thay vì liên tục nhờ backend team tạo endpoint mới, GraphQL cho client mô tả đúng hình dạng nó cần. Độ linh hoạt này có thể giảm over-fetching, under-fetching và khoảng chờ nhỏ xuất hiện mỗi khi thay đổi màn hình biến thành một cuộc thương lượng API.

Nhưng linh hoạt luôn chuyển chi phí sang đâu đó. Trong REST, phần lớn contract nằm rải rác ở các endpoint. Trong GraphQL, phần lớn chi phí tập trung vào schema, resolver, authorization rule, giới hạn query và performance guardrail. Một REST API kém có thể thành một kệ đầy endpoint khó hiểu. Một GraphQL API kém có thể thành một cánh cửa rất đẹp dẫn vào căn phòng mà mỗi query vô tình đánh thức cả tòa nhà. Không phong cách nào tự bảo vệ team khỏi boundary mơ hồ.

Performance là ví dụ rõ. REST có thể over-fetch, nhưng mỗi endpoint cũng có thể được tune, cache và observe như một hình dạng đã biết. GraphQL có thể lấy đúng field được hỏi, nhưng một query có thể che giấu rất nhiều resolver call bên dưới. Nếu thiếu batching, caching, query complexity limit và observability tốt, một request nhìn vô hại có thể thành chuyến đi đắt đỏ qua data graph. GraphQL không xóa backend thinking. Nó làm backend thinking cần thiết hơn vì client có nhiều tự do hơn.

Cấu trúc team quan trọng không kém công nghệ. REST thường hợp khi backend team sở hữu domain API và client consume chúng với nhu cầu tương đối ổn định. GraphQL thường hợp khi có nhiều client, UI thay đổi nhanh và team sẵn sàng xem schema như một product. Điều đó nghĩa là đặt tên field cẩn thận, deprecate field cũ thay vì phá client, document behavior, test authorization và quan sát query pattern thật. Một GraphQL schema không có stewardship rất nhanh biến thành ngăn kéo dùng chung đầy đồ lẫn lộn.

Tôi cũng nghĩ câu hỏi không phải lúc nào cũng là hoặc cái này hoặc cái kia. Nhiều hệ thống trưởng thành dùng REST cho resource operation đơn giản, webhook, file upload, public API hoặc service-to-service contract, đồng thời dùng GraphQL ở edge cho những product screen cần composition linh hoạt. Đôi khi architecture tốt nhất không phải chọn người thắng. Nó là chọn nơi mỗi phong cách giảm friction mà không che quá nhiều chi phí vận hành.

Bài học yên lặng với tôi là API style nên đi theo hình dạng cộng tác. Nếu nỗi đau chính là domain boundary mơ hồ, GraphQL sẽ không cứu team. Nếu nỗi đau chính là client phải chờ vô số endpoint adjustment, sự thuần REST có thể trở nên đắt. Nếu nỗi đau chính là debug production, cách nào cho log, ownership và failure visibility tốt hơn có lẽ là lựa chọn trung thực hơn.

GraphQL và REST đều là cách tạo lời hứa qua một boundary. Câu hỏi hữu ích không phải cách nào hiện đại hơn. Câu hỏi là lời hứa nào team của bạn có thể giữ với ít nhầm lẫn hơn. Nếu bạn từng đi qua một migration từ REST sang GraphQL, hoặc quyết định không migrate, tôi rất muốn nghe điều gì thay đổi sau khi sự hào hứng ban đầu lắng xuống.

Bạn thấy bài viết thế nào?