Menu
ESC

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

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

Đang tải...

GraphQL basics cho BA

API and Technical Fundamentals cho BA Bài 28/60

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

Hãy tưởng tượng bạn là BA của một ứng dụng đặt đồ ăn như ShopeeFood hay GrabFood. Đội mobile gọi cho bạn: "Màn hình chi tiết nhà hàng tải chậm quá, mỗi lần mở lên app phải gọi tới 6 API khác nhau, mạng 3G của user ngoại thành lag kinh khủng." Cùng lúc đó, đội backend than: "Mỗi endpoint của tụi em trả về cả đống field thừa mà app chỉ dùng có một nửa, băng thông tốn vô ích." Hai vấn đề tưởng riêng biệt này thực ra cùng một gốc rễ — và GraphQL chính là một trong những lời giải mà ngành công nghệ đưa ra.

GraphQL không phải là "REST phiên bản mới hơn" hay "công nghệ thay thế REST" như nhiều người lầm tưởng. Nó là một cách tư duy khác về việc client (ứng dụng phía người dùng) lấy dữ liệu từ server. Là BA, bạn sẽ không tự code GraphQL, nhưng bạn sẽ là người ngồi trong cuộc họp quyết định "dự án này dùng REST hay GraphQL", là người viết user story mà đội dev hiện thực bằng GraphQL, và là người giải thích cho stakeholder vì sao chi phí phát triển frontend lại giảm khi chuyển sang GraphQL. Nếu bạn không nắm được khái niệm cốt lõi, bạn sẽ bị "ngợp" trong những cuộc thảo luận kỹ thuật và mất tiếng nói trong các quyết định kiến trúc.

Bài này tập trung vào đúng những gì một BA cần: GraphQL giải quyết vấn đề gì, hoạt động ở mức khái niệm ra sao, khi nào nên chọn nó, và làm sao đọc/viết được một query đơn giản để giao tiếp với đội kỹ thuật.

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

GraphQL là gì, nói cho dễ hiểu

GraphQL là một ngôn ngữ truy vấn cho API (query language for API) do Facebook tạo ra năm 2015. Điểm khác biệt mấu chốt so với REST: thay vì server quyết định mỗi endpoint trả về cái gì, thì client tự mô tả chính xác dữ liệu mình cần, và server trả về đúng từng đó — không thừa, không thiếu.

Một phép so sánh đời thường: REST giống như bạn vào một quán cơm bình dân với các "suất ăn cố định" — suất số 3 luôn có cơm, sườn, canh, rau, dù bạn không ăn rau. GraphQL giống như bạn vào buffet và tự gắp đúng món mình muốn lên đĩa. Bạn cần thông tin gì, bạn "gọi" đúng cái đó.

Hai vấn đề lớn của REST mà GraphQL giải

Over-fetching (lấy dư dữ liệu). Đây là tình huống endpoint trả về nhiều field hơn bạn cần. Ví dụ kinh điển: bạn gọi GET /users/123 để hiển thị tên và avatar trên thanh menu. Nhưng endpoint này được thiết kế "đa dụng", nên nó trả về luôn 50 field: địa chỉ, ngày sinh, lịch sử đăng nhập, số điện thoại, danh sách đơn hàng... Bạn chỉ cần 2 field nhưng phải tải về 50. Với một user thì không sao, nhưng nhân lên hàng triệu request mỗi ngày trên mạng di động chậm, đó là lãng phí băng thông và làm app ì ạch.

Với GraphQL, bạn chỉ cần viết:

query {
  user(id: 123) {
    name
    avatarUrl
  }
}

Và server trả về đúng:

{
  "data": {
    "user": {
      "name": "Nguyễn Văn An",
      "avatarUrl": "https://.../an.jpg"
    }
  }
}

Under-fetching (lấy thiếu dữ liệu, phải gọi nhiều lần). Đây là tình huống ngược lại: một màn hình cần dữ liệu từ nhiều nguồn, nên phải gọi nhiều endpoint. Ví dụ màn hình chi tiết một bài viết blog: bạn gọi GET /posts/45 lấy nội dung bài, rồi GET /users/7 lấy thông tin tác giả, rồi GET /posts/45/comments lấy bình luận, rồi với mỗi comment lại gọi GET /users/{id} lấy thông tin người bình luận. Có khi 5-6 round-trip (lượt đi-về giữa client và server) chỉ để dựng một màn hình. Hiện tượng gọi lặp này còn gọi là N+1 problem ở phía client.

Với GraphQL, tất cả gói trong một request duy nhất:

query {
  post(id: 45) {
    title
    content
    author {
      name
    }
    comments {
      text
      author {
        name
      }
    }
  }
}

Bạn thấy đặc tính "graph" (đồ thị) ở đây: từ post đi tới author, từ post đi tới comments, từ mỗi comment lại đi tới author của nó. GraphQL cho phép bạn "đi theo các mối quan hệ" trong dữ liệu chỉ trong một lần hỏi.

Schema — trái tim của GraphQL

Mỗi API GraphQL có một schema — bản hợp đồng mô tả tất cả các loại dữ liệu (type) và các trường (field) mà client được phép truy vấn. Schema giống như "thực đơn buffet": nó liệt kê mọi món có sẵn để client biết được mình có thể gọi gì.

type User {
  id: ID!
  name: String!
  email: String
  posts: [Post!]
}

type Post { id: ID! title: String! author: User! }

Dấu ! nghĩa là field bắt buộc có (non-null), [Post!] nghĩa là một mảng các Post. Là BA, schema chính là tài liệu bạn cần đọc kỹ nhất, vì nó phản ánh trực tiếp mô hình nghiệp vụ. Nếu schema thiếu mối quan hệ "đơn hàng thuộc về khách hàng", đó là dấu hiệu yêu cầu nghiệp vụ chưa được phản ánh đúng.

Ba loại thao tác: Query, Mutation, Subscription

  • Query: đọc dữ liệu (tương đương GET trong REST).
  • Mutation: thay đổi dữ liệu — tạo, sửa, xóa (tương đương POST/PUT/PATCH/DELETE).
  • Subscription: nhận dữ liệu real-time khi có thay đổi (server đẩy dữ liệu về, dùng cho chat, thông báo).
Một điểm quan trọng cho BA: trong GraphQL, thông thường chỉ có một endpoint duy nhất (ví dụ https://api.shop.vn/graphql), và mọi request đều là POST tới endpoint đó, với nội dung query nằm trong body. Điều này khác hẳn REST nơi mỗi tài nguyên có một URL riêng — và nó kéo theo nhiều hệ quả về caching, monitoring mà ta sẽ bàn ở phần lỗi thường gặp.

Khi nào nên dùng GraphQL, khi nào không

GraphQL tỏa sáng khi: ứng dụng có nhiều client khác nhau (web, iOS, Android) với nhu cầu dữ liệu khác nhau; dữ liệu có nhiều mối quan hệ phức tạp; frontend thay đổi giao diện liên tục và không muốn phụ thuộc backend mỗi lần đổi.

GraphQL không phải lựa chọn tốt khi: API rất đơn giản (vài endpoint CRUD cơ bản — REST gọn hơn); cần tận dụng HTTP caching mạnh ở tầng CDN; đội ngũ chưa có kinh nghiệm và dự án nhỏ, gấp. Như mọi quyết định kiến trúc, đây là bài toán đánh đổi, không có đáp án đúng tuyệt đối.

Tình huống thực tế

Ví dụ 1: App đặt phòng khách sạn của một startup du lịch VN

Một startup OTA (online travel agency) ở TP.HCM, gọi là "Tripzy", có app đặt phòng khách sạn. Màn hình chi tiết khách sạn ban đầu dùng REST, phải gọi 7 endpoint: thông tin khách sạn, danh sách phòng, giá, đánh giá, tiện ích, ảnh, vị trí trên bản đồ. Trên mạng 4G yếu ở các tỉnh, thời gian tải trung bình là 4,2 giây — và họ đo được rằng cứ mỗi giây tải chậm, tỷ lệ thoát màn hình tăng khoảng 11%.

Đội kỹ thuật chuyển màn hình này sang GraphQL: gói toàn bộ 7 nguồn dữ liệu vào một query duy nhất. Số request giảm từ 7 xuống 1, thời gian tải trung bình giảm còn 1,8 giây. Quan trọng hơn với BA: đội mobile không cần chờ backend làm endpoint mới mỗi khi thiết kế màn hình thay đổi — họ chỉ việc sửa query lấy thêm/bớt field.

Bài học rút ra: GraphQL giải bài toán under-fetching rất hiệu quả cho các màn hình "tổng hợp" nhiều nguồn dữ liệu. Là BA, khi bạn thấy một màn hình yêu cầu dữ liệu từ nhiều thực thể khác nhau, đó là tín hiệu để đặt câu hỏi: "Liệu GraphQL có giúp giảm số request và tăng tốc không?"

Ví dụ 2: Nền tảng thương mại điện tử với 3 loại client

Một sàn TMĐT giả định "MuaSamViet" có ba ứng dụng dùng chung backend: web cho khách mua, app mobile cho khách, và app cho shipper. Với REST, đội backend phải tạo các endpoint riêng cho từng nhu cầu — ví dụ /orders/mobile trả ít field cho app (tiết kiệm data), /orders/web trả nhiều field cho web. Mỗi lần một client cần thêm thông tin, lại một vòng "frontend mở ticket — backend làm endpoint — deploy — chờ". Trung bình mất 3-5 ngày làm việc cho một thay đổi nhỏ.

Sau khi chuyển sang GraphQL với một schema chung, app shipper chỉ query order { id, address, customerPhone, status }, còn web query thêm order { items { name, price }, paymentMethod, invoice }. Cùng một backend, mỗi client tự lấy đúng phần mình cần. Thời gian cho các thay đổi nhỏ ở frontend giảm xuống còn dưới một ngày, vì phần lớn không còn cần backend can thiệp.

Bài học rút ra: GraphQL đặc biệt giá trị khi có nhiều client với nhu cầu dữ liệu khác nhau trên cùng một backend. Lợi ích lớn nhất không chỉ là kỹ thuật mà là tốc độ ra tính năng — điều mà BA và Product Owner luôn quan tâm. Khi viết business case cho việc áp dụng GraphQL, hãy nhấn mạnh khía cạnh giảm thời gian phối hợp giữa các đội.

Ví dụ 3: Khi GraphQL là lựa chọn SAI

Một phòng IT nội bộ của một ngân hàng VN xây dựng một dịch vụ tra cứu tỷ giá đơn giản: chỉ có 2 endpoint, dữ liệu thay đổi mỗi 5 phút, và được nhiều hệ thống khác gọi với lưu lượng cực lớn. Một kiến trúc sư đề xuất dùng GraphQL "cho hiện đại". Sau 2 tháng, họ phát hiện vấn đề: vì mọi request GraphQL đều là POST tới một endpoint, họ không thể tận dụng caching ở tầng CDN (vốn cache rất tốt cho GET theo URL). Kết quả là server phải xử lý lượng request khổng lồ mà lẽ ra CDN có thể gánh, chi phí hạ tầng tăng vọt. Họ phải quay lại REST.

Bài học rút ra: GraphQL không phải lúc nào cũng tốt hơn. Với API đơn giản, dữ liệu ít thay đổi và cần caching mạnh, REST với HTTP caching truyền thống thường là lựa chọn đúng. Là BA, đừng để bị cuốn theo "công nghệ thời thượng" — hãy luôn hỏi: vấn đề thực sự ta đang giải là gì, và công nghệ này có phù hợp với bối cảnh không?

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

Đây là quy trình để một BA tiếp cận và làm việc với một API GraphQL:

Bước 1 — Tìm và đọc schema. Hỏi đội dev: "API GraphQL của mình có schema ở đâu?" Hầu hết dự án dùng công cụ GraphiQL hoặc Apollo Studio — một giao diện web cho phép bạn xem toàn bộ type, field và thử query trực tiếp trên trình duyệt. Đây là điểm khởi đầu để hiểu mô hình dữ liệu.

Bước 2 — Đối chiếu schema với yêu cầu nghiệp vụ. Với mỗi user story, hãy xác định màn hình cần hiển thị những thông tin gì, rồi kiểm tra trong schema xem các field đó đã có chưa và quan hệ giữa chúng có đúng không. Nếu thiếu, đó là một yêu cầu cần làm rõ với đội backend.

Bước 3 — Tự viết thử một query. Bạn không cần biết lập trình để viết query GraphQL. Cú pháp rất gần với việc "vẽ cây dữ liệu bạn muốn". Mở GraphiQL và gõ thử:

query {
  product(id: "A100") {
    name
    price
    seller {
      shopName
      rating
    }
  }
}

Tính năng auto-complete (gợi ý tự động) trong GraphiQL sẽ giúp bạn biết field nào có sẵn — gõ tới đâu nó gợi ý tới đó. Đây là cách nhanh nhất để hiểu API.

Bước 4 — Phân biệt query và mutation khi viết acceptance criteria. Khi viết tiêu chí chấp nhận cho một tính năng, hãy nói rõ thao tác là đọc (query) hay ghi (mutation). Ví dụ: "Khi user nhấn Lưu, hệ thống thực hiện mutation updateProfile với các field name, phone; nếu thành công trả về profile đã cập nhật."

Bước 5 — Làm rõ cách xử lý lỗi. GraphQL có cách trả lỗi khác REST: thay vì dùng status code (404, 500...), một response GraphQL thường trả về HTTP 200 nhưng có một mảng errors riêng bên cạnh data. Hãy thống nhất với đội dev về cấu trúc lỗi để thiết kế thông báo cho người dùng cho đúng.

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

Lỗi 1: Nghĩ GraphQL thay thế hoàn toàn REST. Nhiều BA mới nghĩ phải "chọn một trong hai" cho cả hệ thống. Thực tế, rất nhiều công ty dùng cả hai song song: GraphQL cho các màn hình phức tạp, REST cho các tác vụ đơn giản và webhook. Đừng tuyệt đối hóa.

Lỗi 2: Quên rằng GraphQL khó cache hơn. Vì mọi thứ qua một endpoint POST, kỹ thuật caching truyền thống của HTTP/CDN không áp dụng trực tiếp được. Khi thảo luận về hiệu năng cho dữ liệu đọc nhiều, hãy hỏi đội dev họ xử lý caching thế nào.

Lỗi 3: Bỏ qua rủi ro về hiệu năng của query "quá tham lam". Vì client tự do lấy dữ liệu, một query lồng quá sâu (ví dụ user → posts → comments → author → posts...) có thể khiến server phải xử lý cực nặng và làm sập hệ thống. Đây là rủi ro bảo mật/hiệu năng có thật. Mẹo: hỏi đội dev về query depth limitingrate limiting đã được áp dụng chưa.

Lỗi 4: Nhầm "một endpoint" nghĩa là "đơn giản hơn để giám sát". Thực ra ngược lại — vì mọi request đều tới /graphql, việc đo lường "endpoint nào chậm" trở nên khó hơn, phải phân tích theo từng query/field. Hãy lưu ý điều này khi bàn về observability và logging.

Mẹo vàng cho BA: Khi nhận một tính năng mới, hãy tự vẽ "cây dữ liệu" mà màn hình cần — gốc là thực thể chính, các nhánh là thông tin liên quan. Cây này chính là bản nháp của một GraphQL query, và nó giúp bạn giao tiếp với dev cực kỳ hiệu quả, dù cuối cùng dự án có dùng GraphQL hay không.

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

  • Phân biệt khái niệm: Cho màn hình "trang cá nhân người dùng" hiển thị: tên, avatar, 5 bài viết gần nhất, và với mỗi bài là số lượt thích. Hãy chỉ ra với REST thì có nguy cơ over-fetching hay under-fetching, và GraphQL giải quyết ra sao.
  • Viết query: Dựa trên schema sau, hãy viết một query GraphQL lấy tên nhà hàng, đánh giá trung bình, và danh sách 3 món ăn (tên + giá) của nhà hàng có id "R88".
   type Restaurant { id: ID!  name: String!  rating: Float  dishes: [Dish!] }
   type Dish { id: ID!  name: String!  price: Int! }
   
  • Ra quyết định: Một dự án nội bộ cần API trả về danh sách 12 ngày lễ trong năm, dữ liệu gần như không đổi, được gọi vài triệu lần/ngày. Hãy lập luận trong 4-5 câu nên dùng REST hay GraphQL và vì sao.
  • Viết acceptance criteria: Cho tính năng "đổi mật khẩu", hãy viết tiêu chí chấp nhận có nêu rõ đây là mutation, input cần gì, và response khi thành công/thất bại trông như thế nào.
  • Tư duy phản biện: Liệt kê 3 câu hỏi bạn sẽ đặt cho đội kỹ thuật trước khi đồng ý chuyển một module quan trọng từ REST sang GraphQL.

Tóm tắt

GraphQL là một ngôn ngữ truy vấn cho API, ra đời để giải hai bài toán nhức nhối của REST: over-fetching (lấy dư field không cần) và under-fetching (phải gọi nhiều endpoint cho một màn hình). Ý tưởng cốt lõi là client tự mô tả chính xác dữ liệu mình cần và nhận về đúng từng đó, thường qua một endpoint duy nhất.

Những điểm BA cần nhớ: schema là "hợp đồng" mô tả mô hình dữ liệu và là tài liệu quan trọng nhất để đọc; có ba loại thao tác là Query (đọc), Mutation (ghi) và Subscription (real-time); GraphQL mạnh khi có nhiều client với nhu cầu khác nhau và dữ liệu nhiều quan hệ, nhưng yếu ở caching và có rủi ro về query quá nặng. Đừng coi nó là "thay thế REST" mà là một công cụ trong hộp đồ nghề — chọn đúng theo bối cảnh bài toán. Quan trọng nhất, kỹ năng "vẽ cây dữ liệu cho mỗi màn hình" sẽ giúp bạn giao tiếp với đội kỹ thuật và viết yêu cầu sắc bén hơn, bất kể công nghệ cuối cùng là gì.