5 điểm bởi GN⁺ 2025-12-15 | 2 bình luận | Chia sẻ qua WhatsApp
  • GraphQL cố gắng giải quyết vấn đề yêu cầu thừa dữ liệu, nhưng trong phần lớn môi trường doanh nghiệp, đây đã là vấn đề được giải bằng cách khác
  • Trong các hệ thống doanh nghiệp nơi kiến trúc BFF (Backend for Frontend) đã trở nên phổ biến, lợi thế chính của GraphQL giảm đi đáng kể
  • Độ phức tạp khi triển khai, khả năng quan sát suy giảm, vấn đề cache, ràng buộc về ID, sự bất tiện khi xử lý tệp khiến chi phí trong môi trường vận hành thực tế tăng cao
  • REST đơn giản, nhanh và dễ xử lý lỗi cũng như onboarding, nên hiệu quả hơn trong môi trường đội ngũ quy mô lớn
  • Kết luận là GraphQL hữu ích trong một số tình huống cụ thể, nhưng là một lựa chọn quá mức đối với phần lớn doanh nghiệp

Vấn đề mà GraphQL muốn giải quyết

  • Mục tiêu cốt lõi của GraphQL là ngăn overfetching (yêu cầu thừa dữ liệu không cần thiết)
    • Client chỉ yêu cầu các trường cần thiết để giảm việc truyền dữ liệu dư thừa
    • Có ưu điểm là không cần sửa backend mỗi khi phát sinh yêu cầu UI mới
  • Tuy nhiên, trong môi trường thực tế, cấu trúc lý tưởng này không khớp với hiện thực phức tạp

Overfetching đã được giải quyết bằng BFF

  • Phần lớn frontend doanh nghiệp sử dụng lớp BFF (Backend for Frontend)
    • Kết hợp dữ liệu theo đúng nhu cầu UI, hợp nhất nhiều lời gọi downstream và che giấu độ phức tạp của backend
  • BFF dựa trên REST vốn đã có thể chỉ trả về dữ liệu cần thiết, nên ưu điểm của GraphQL bị trùng lặp
  • Nếu lớp GraphQL lấy dữ liệu từ REST API, thì overfetching chỉ đơn giản chuyển xuống thấp hơn một tầng
  • GraphQL có thể hữu ích khi nhiều trang dùng chung một endpoint, nhưng
    • lợi ích đó chỉ ở mức chấp nhận thêm gánh nặng cấu hình và bảo trì để đổi lấy việc tiết kiệm vài kilobyte

Độ phức tạp triển khai và suy giảm năng suất

  • GraphQL mất nhiều thời gian triển khai hơn và phức tạp hơn REST
    • Cần thêm công việc như định nghĩa schema, type, resolver, data source
    • Tồn tại gánh nặng duy trì sự đồng bộ giữa schema và client
  • GraphQL tối ưu cho tiêu thụ (sự thuận tiện của client) nhưng đánh đổi bằng sản xuất (tốc độ phát triển server)
  • Trong môi trường doanh nghiệp, tốc độ phát triển và sự đơn giản quan trọng hơn

Vấn đề về khả năng quan sát và giám sát

  • Cơ chế mã trạng thái HTTP của GraphQL không nhất quán
    • Ngay cả phản hồi 200 cũng có thể chứa lỗi, khiến việc phân biệt thành công/thất bại khi giám sát trở nên khó khăn
  • REST phân tách rõ ràng bằng 2XX/4XX/5XX nên việc lọc trên dashboard trực quan hơn
  • Có thể tùy biến bằng Apollo v.v., nhưng điều này lại gây ra thiết lập bổ sung và gánh nặng tinh thần
  • Khi xử lý sự cố trong vận hành, việc xác định vấn đề khó và phức tạp hơn REST

Giới hạn thực tế của cache

  • Normalized caching của Apollo mạnh về lý thuyết nhưng trong thực tế lại mong manh và phức tạp
    • Những query chỉ khác một trường cũng bị xem là riêng biệt, nên cần liên kết thủ công
    • Việc debug cache trở thành một vấn đề riêng
  • Ngược lại, REST chỉ cần cache toàn bộ phản hồi nên ổn định và dễ bảo trì

Vấn đề với ràng buộc trường ID

  • Apollo giả định mọi object đều có trường id hoặc _id
    • Nhiều API doanh nghiệp không có ID duy nhất, hoặc không phải định danh toàn cục
  • Để khớp với giả định này, BFF phải thêm logic tạo ID cục bộ
    • Kết quả là tăng thêm trường và logic không cần thiết, làm triệt tiêu hiệu quả giảm overfetching

Sự kém hiệu quả của upload và download tệp

  • GraphQL không phù hợp để xử lý dữ liệu nhị phân
    • Trên thực tế thường trả về URL tải xuống, còn tệp thì được truyền qua REST
    • Nếu đưa dữ liệu lớn như PDF vào phản hồi GraphQL sẽ gây suy giảm hiệu năng
  • Vì vậy, lý tưởng về một “API duy nhất” của GraphQL bị phá vỡ

Onboarding và đường cong học tập

  • Phần lớn lập trình viên đã có nhiều kinh nghiệm với REST, còn GraphQL thì cần học thêm
    • Cần nắm các khái niệm mới như schema, resolver, cách tạo query, quy tắc cache, xử lý lỗi
  • Điều này dẫn đến tốc độ onboarding của đội ngũ giảm xuống
  • REST là cách tiếp cận “nhàm chán nhưng có khả năng mở rộng cao”, nên phù hợp với các đội ngũ lớn

Độ phức tạp của xử lý lỗi

  • Phản hồi lỗi của GraphQL phức tạp với trường nullable, partial data, mảng errors, mã trạng thái mở rộng
    • Cần lần theo resolver nào đã thất bại
  • REST chỉ cần phân biệt bằng 400/500 nên dễ hiểu và dễ debug hơn

Kết luận: GraphQL là công nghệ ngách

  • GraphQL là một công cụ hiệu quả trong một số tình huống cụ thể
    • Nhưng trong phần lớn môi trường doanh nghiệp, vấn đề đã được giải bằng BFF và REST
    • Thách thức chính không phải là overfetching mà là khả năng quan sát, độ tin cậy và tốc độ
  • Kết quả là GraphQL giải quyết một vấn đề hẹp nhưng lại tạo ra độ phức tạp rộng hơn
  • Kết luận là: “GraphQL không tệ, nhưng trong đa số trường hợp thì không cần thiết

2 bình luận

 
colus001 2025-12-16

Dù có cả ưu và nhược điểm, nhưng việc thiết kế dữ liệu và kiểm soát truy cập ở cấp độ schema, rồi mỗi khi thêm thứ gì đó lại phải thêm vào REST API, như vậy có vẻ vẫn tốt hơn là để sau này cuối cùng trả về tất cả. Nhược điểm thì rõ ràng, nhưng ưu điểm cũng rất rõ ràng nên haha

 
GN⁺ 2025-12-15
Ý kiến trên Hacker News
  • Tôi không đồng ý với bài viết cho rằng vấn đề chính của GraphQL là overfetching
    Theo tôi, lợi thế thực sự là (a) nó ép buộc một hợp đồng dựa trên kiểu chặt chẽ, và (b) tiến hóa schema dễ hơn nhiều
    Nhờ hệ thống kiểu, input và output luôn tuân theo hình dạng đã được định nghĩa, và nếu dùng scalar type tùy chỉnh (ví dụ: số điện thoại, email, v.v.) thì có thể giảm đáng kể bug và vấn đề bảo mật
    Ngoài ra, việc thêm field mới hay loại bỏ field cũ đều đã được chuẩn hóa, nên cả server lẫn client đều có ít gánh nặng nhận thức hơn

    • Tôi cũng không nghĩ overfetching là vấn đề cốt lõi
      Lý do tôi dùng GraphQL là vì khả năng tổ hợp và tiến hóa API. Đặc biệt trong các hệ thống quy mô lớn có cấu trúc M:N, luồng “client mô tả thứ mình cần → server tổ hợp → domain service xử lý” về lâu dài dễ quản lý hơn nhiều
      Khi kết hợp với observability tốt, nó trở thành một nền tảng rất mạnh cho truy cập dữ liệu
    • Nếu tạo type TypeScript từ spec OpenAPI thì cũng có hợp đồng hai chiều, nên phần đó không phải là vấn đề mà GraphQL cần giải quyết
    • Tôi cũng cho rằng tính hợp đồng mạnh của GraphQL là lý do lớn nhất
      Một điểm nữa là resolver tái sử dụng được và federation khá dễ. Với REST thì chuyện này khá phiền
    • Việc pruning request và response bằng zod thì đơn giản. Chỉ vì lý do đó thì tôi sẽ không đưa GQL vào
      Về tiến hóa schema, Protobuf cũng xử lý tốt
    • Tôi không thấy GraphQL khác gì so với giao tiếp bằng protobuf. Cả hai đều parse theo đúng định nghĩa
  • Lợi thế thực sự của GraphQL là có thể ghép dữ liệu UI từ các mảnh nhỏ
    Như trong video này, nếu tận dụng fragment colocation thì khi chỉnh sửa component con cũng không ảnh hưởng đến phần khác
    Vì query được tự động tạo dựa trên fragment, nên khi xóa field cũng giảm nguy cơ làm hỏng component khác
    Nếu quy mô nhỏ hoặc tốc độ phát triển không quá quan trọng, GraphQL có thể trông như một khoản đầu tư quá mức

    • Tôi nghĩ Apollo đã dẫn mọi người đi sai hướng nên họ không cảm nhận được lợi thế thực sự của GraphQL
      Colocation thực sự là một khái niệm mang tính cách mạng, nhưng Apollo gần như không nhắc đến điều này
    • Vấn đề không phải GraphQL mà là Apollo Client
      Tài liệu của Relay vẫn còn thiếu, nhưng khái niệm Entrypoint thì rất tuyệt
    • Tôi đồng ý với fragment masking
      Nhưng cách triển khai của graphql-codegen lại có độ tương thích plugin kém, nên chúng tôi phải tự viết plugin
      Toàn bộ hệ sinh thái thiếu tính nhất quán
  • Nói overfetching là vấn đề cốt lõi của GraphQL thì hơi phóng đại
    Tôi cho rằng GraphQL là công cụ xử lý impedance mismatch mà ORM giải quyết, nhưng ở cấp độ client
    Dùng nó mà không có tooling dựa trên compiler như Relay là một anti-pattern
    Dạo này AI tự sinh data layer, nên có vẻ nhu cầu với GraphQL đang giảm đi

    • Tôi đồng ý với ý “không nên dùng GraphQL nếu không có compiler”, nhưng không chắc điều đó có dễ hơn việc viết vài dòng code trong BFF hay không
    • Tôi đề xuất extension VSCode của Isograph như một ví dụ về tooling GraphQL tốt
      Chỉ cần chọn một field không tồn tại là nó tự sinh giúp, nên trải nghiệm phát triển (DevEx) rất tốt
    • URQLgql.tada là các công cụ phía client rất tuyệt
    • Tôi tò mò mọi người đang dùng gì cho tooling GraphQL. IntelliJPostman cũng hỗ trợ rất tốt
    • Tôi không đồng ý với ý rằng overfetching không phải vấn đề lớn
      Sự chậm chạp của web hiện đại phần lớn đến từ truyền dữ liệu dư thừa. Trên thực tế, nhiều ứng dụng hoạt động với hiệu suất dưới 0.5%
  • Tôi đã dùng GraphQL từ năm 2016
    Về bản chất, GraphQL là một đặc tả RPC. Nó được triển khai dưới dạng ánh xạ “Action(Args) → ResultType” của server
    Thay vì nhiều endpoint như REST, GraphQL hoạt động qua một endpoint /query duy nhất thông qua resolver map
    Rốt cuộc nó cũng là một cấu trúc mà input và output được định nghĩa bằng kiểu giống như OpenAPI hay gRPC

    • Tôi đã dùng GraphQL từ năm 2015, và nếu dùng GraphQL mà không có Relay thì rất có thể bạn sẽ không cảm nhận được điểm mạnh thực sự
      Apollo có khá hơn một chút sau khi thêm fragment masking, nhưng tư duy lấy Relay làm trung tâm vẫn rất quan trọng
    • Cách giải thích này quá đơn giản. Nó đã bỏ qua hoàn toàn quá trình diễn giải query
    • Bạn đã bỏ sót điểm là client có thể chỉ định các field cần request
    • Có vẻ không liên quan nhiều tới bài gốc
    • GraphQL hiệu quả nhất khi toàn bộ trang React gom yêu cầu từ các component con thành một query lớn duy nhất,
      rồi backend chuyển nó thành một truy vấn SQL duy nhất để xử lý
      Resolver chỉ nên dùng ngoại lệ cho dữ liệu không thể lấy trực tiếp từ DB
  • Trước đây khi dẫn dắt một team, FE muốn GraphQL nên tôi đã đưa nó vào
    Kết quả là mỗi trang đều lấy mọi dữ liệu bằng một query khổng lồ, và khi chỉnh sửa thì lại gửi toàn bộ JSON blob lên lần nữa
    Ứng dụng vẫn chạy được, nhưng rồi công ty pivot nên đoạn code đó cũng biến mất
    Trên thực tế, có vẻ nhiều dự án GraphQL cũng kết thúc theo kiểu triển khai cho có hình thức như vậy

  • Luồng xác thực (auth) của GraphQL là một trong những bài toán khó nhất
    Vì resolver được gọi trong nhiều ngữ cảnh khác nhau, nên phải tính đến mọi trường hợp
    Độ phức tạp và chi phí tư duy quá lớn, cuối cùng lại phải khóa field
    Tôi từng tự làm graphql-autharoo, nhưng vẫn chưa đủ
    Phần lớn chức năng có thể được triển khai đơn giản hơn nếu không dùng GraphQL

    • Ngay cả ở GitHub thì phân quyền (authz) cũng là vấn đề lớn
      Phải thêm quyền chi tiết cho từng resource GraphQL, nên cho đến khi toàn bộ resource được cập nhật xong thì query vẫn không chạy được
      Nó nặng nề đến mức người ta phải nói rằng “thà làm lại bằng REST còn hơn
    • Tôi muốn hỏi liệu bạn đã thử xác thực dựa trên decorator chưa
      Tôi nghĩ tốt hơn là dùng một server framework hoàn chỉnh thay vì tự ghép mọi thứ lại
  • GraphQL nhìn bề ngoài thì rất hay, nhưng trên thực tế là một công nghệ càng về lâu dài càng khó bảo trì
    Cũng như nhiều công nghệ khác, nó rút ra bài học rằng cuối cùng thì bánh xe vẫn chỉ là bánh xe

  • Điểm mạnh của GraphQL là chỉ cần thêm field vào schema thì mọi client đều có thể query ngay lập tức
    Những yêu cầu từ FE kiểu “hãy thêm field này nữa” biến mất, nên việc cộng tác trở nên đơn giản hơn
    Ngoài ra cũng dễ tạo schema snapshot để phát hiện thay đổi trong integration test
    Tôi thấy nó nhất quán hơn REST, nhưng đó chỉ là trải nghiệm cá nhân

    • Nhưng lợi thế đó cũng là con dao hai lưỡi
      Vì có thể request dây chuyền từ A đến E, nên dễ dẫn đến suy giảm hiệu năng hoặc sự gắn chặt giữa frontend và cấu trúc dữ liệu
    • Dạo này hầu hết đều là môi trường TypeScript full-stack, nên kiểu vấn đề cộng tác này đã giảm đi
      React giờ cũng lấy SSR dựa trên framework và server component làm mặc định
      Cuối cùng thì xu hướng đang đi theo hướng TypeScript hợp nhất client và server
  • Tôi tò mò GraphQL ngăn vấn đề tải DB hoặc query kém hiệu quả như thế nào
    Chẳng phải query ác ý có thể làm nổ tung trạng thái nội bộ sao?

    • Hầu hết server đều đặt giới hạn độ phức tạp (chi phí) của query, và nếu vượt ngưỡng thì sẽ từ chối request
  • Tôi đang thử GraphQL vì REST quá nhàm chán
    Tôi thích điểm là server và client có thể đồng thuận request·response ở thời điểm compile
    Giá mà các blog đừng chỉ nói “cái này dở” mà còn đưa ra cả công nghệ thay thế

    • Nếu bạn thích TypeScript isomorphic, thì tRPC là một lựa chọn thay thế gọn gàng hơn GraphQL
      Cả hai công nghệ đều giải quyết rất tốt bài toán hợp đồng client-server