GraphQL với Spring Boot
Query, mutation và subscription

Query, mutation và subscription

Lộ trình từ selection set và variables đến mutation, lỗi, pagination, filtering và subscription với Spring for GraphQL.

Nhóm Query, mutation và subscription là điểm nối giữa contract GraphQL và các use case mà client thực sự gọi. Bạn sẽ bắt đầu từ cách chọn dữ liệu bằng selection set, sau đó tổ chức variables, arguments và fragments, thiết kế operation ghi với input/payload, đọc lỗi, rồi mở rộng sang danh sách có pagination/filtering và luồng realtime.

Nhóm này trả lời hai câu hỏi song song: client nên viết operation như thế nào và server Spring for GraphQL cần bảo đảm điều gì phía sau contract đó. Các bài trong nhóm ưu tiên mental model và response shape trước, rồi mới dẫn sang transport, lifecycle, authorization, data source và khả năng vận hành.

Phạm vi và giả định

Các SDL, query, variables, JSON và Java fragment trong trang này cùng các bài liên quan chỉ là ví dụ minh họa tĩnh. Repository là docs-only và không kèm backend Spring Boot runnable, nên trang này không tuyên bố build, startup, resolver, WebSocket hay response runtime đã được kiểm chứng. Khi áp dụng vào project thật, hãy đối chiếu version Spring Boot/Spring for GraphQL, schema đang nạp, endpoint, resolver và data source thực tế.

Mục lục

Trang này dành cho ai?

Trang này phù hợp với:

  • Người đã biết GraphQL có schema, type, field và operation nhưng muốn chuyển sang các request gần với ứng dụng thật.
  • Java/Spring developer muốn hiểu ranh giới giữa SDL, resolver, service, repository, event source và transport trước khi viết implementation.
  • Frontend developer hoặc người xây client cần kiểm soát response shape, variables, lỗi, danh sách và realtime.
  • Người đã đi qua nhóm Nền tảng và Bắt đầu, muốn có bản đồ trước khi đọc từng bài chuyên đề.

Nếu GraphQL còn mới hoàn toàn, hãy bắt đầu từ GraphQL là gì? và Mô hình request/response. Nếu chưa từng tạo endpoint Spring Boot, đi qua Tạo schema đầu tiên và Viết query đầu tiên trước.

Điều kiện tiên quyết

Bạn nên có các nền tảng sau:

  • Hiểu schema là contract, phân biệt output object với scalar, và biết object hoặc list object cần selection set. Có thể ôn Scalar, object và field và List và nullable.
  • Đọc được một operation gồm query, mutation hoặc subscription, cùng selection set, operation name và variables.
  • Biết execution result có thể gồm data, errors và metadata tùy implementation. Không dùng HTTP status, đặc biệt HTTP 200, làm tín hiệu thành công duy nhất.
  • Nếu muốn theo các ví dụ Spring, nên biết Java cơ bản, Spring Boot và cách chạy một project bằng Maven hoặc Gradle. Nhóm Bắt đầu cung cấp phần setup, dependency, schema, GraphiQL và curl/Postman.

Không cần biết trước GraphQL Java, Reactor hoặc WebSocket để đọc phần nhập môn. Các khái niệm implementation đó sẽ được giới thiệu khi cần và được nối sang nhóm Tích hợp Spring for GraphQL.

Mục tiêu học tập

Sau khi đọc nhóm này theo lộ trình, bạn có thể:

  • Chọn đúng loại operation cho việc đọc snapshot, thay đổi trạng thái hoặc nhận event stream; đồng thời phân biệt loại operation với HTTP/WebSocket transport.
  • Viết query có selection set, nested field và alias; giữ query document ổn định bằng variables, arguments và fragments.
  • Thiết kế mutation với input object và payload có ngữ nghĩa, thay vì gửi một JSON mơ hồ hoặc trả về một Boolean không giải thích được kết quả.
  • Phân loại lỗi parse/validation/coercion, lỗi nghiệp vụ và lỗi execution; biết khi nào đọc top-level errors và khi nào đọc lỗi typed trong payload.
  • Đánh giá pagination, filtering và sorting như một phần của schema contract, gồm page size, thứ tự ổn định, cursor/offset và input có khả năng mở rộng.
  • Mô tả vòng đời subscription từ subscribe đến event, complete, reconnect và cleanup; biết những điểm cần kiểm tra về authentication, authorization và backpressure.
  • Biết lúc nào mental model đã đủ cho client và lúc nào cần đi sang bài triển khai Spring for GraphQL về mapping, binding, context hoặc request lifecycle.

Mental model của ba operation

Hãy xem operation là yêu cầu ở lớp GraphQL, không phải tên của URL. Client gửi operation, variables và selection set; schema kiểm tra contract; execution engine gọi resolver; implementation phía sau lấy dữ liệu hoặc phát event; kết quả quay lại dưới dạng data, errors và extensions nếu server có dùng.

Client: operation + variables + selection setSchema và execution engine: parse, validate, coerce, executeSpring for GraphQL: root mapping và nested mappingService / repository / data source / event sourceExecution result: data + errors + extensions
Client: operation + variables + selection setSchema và execution engine: parse, validate, coerce, executeSpring for GraphQL: root mapping và nested mappingService / repository / data source / event sourceExecution result: data + errors + extensions
Operation qua schema và Spring mapping

Sơ đồ trên là mental model, không phải bằng chứng về số lần gọi service, query database hoặc thứ tự resolver trong một backend cụ thể. Một HTTP request GraphQL vẫn có thể tạo nhiều lời gọi phía server. Một subscription có thể giữ một Publisher mở nhưng vẫn cần policy riêng cho event source và connection.

Query đọc snapshot

query thường dùng để đọc dữ liệu hoặc trạng thái tại thời điểm gọi. Client quyết định response shape bằng selection set, có thể truyền arguments để tìm kiếm, filter hoặc phân trang. Query không nên tạo side effect chỉ vì resolver đang dùng cùng một service với mutation.

Hãy bắt đầu với Query, selection set và alias, rồi chuyển sang Variables, arguments và fragments. Hai bài này xây vocabulary cần thiết để đọc một object lồng nhau, gọi cùng field nhiều lần và tái sử dụng selection mà không nối chuỗi query động.

Mutation thay đổi trạng thái

mutation biểu diễn một use case có thể thay đổi state hoặc tạo side effect. Input mô tả dữ liệu client được phép gửi; payload mô tả kết quả server muốn công khai. GraphQL không tự mở transaction, không tự bảo đảm idempotency và không tự quyết định rollback khi service gọi nhiều hệ thống.

Đọc Mutation và input/payload sau khi đã nắm variables. Tiếp đó, dùng Xử lý lỗi trong mutation để phân biệt lỗi request với outcome nghiệp vụ và exception execution. Khi áp dụng, hãy để service sở hữu invariant, authorization và transaction boundary; resolver chủ yếu bind input và gọi use case.

Subscription nhận event stream

subscription dùng cho một đăng ký dài hạn, trong đó server có thể gửi nhiều execution result khi event phù hợp xuất hiện. Subscription không tự tạo event và không đồng nghĩa với polling. WebSocket là một transport phổ biến, nhưng operation type và transport vẫn là hai lớp khác nhau.

Bài Subscription và WebSocket đi từ schema và operation đến protocol message, authentication, reconnect, fan-out, backpressure và cleanup. Đây là chặng cần đọc sau khi hiểu selection set và variables, vì mỗi event vẫn phải được hoàn tất theo selection set của client.

Cách phân lớp nội dung

Nhóm này có một đường học từ contract đến vận hành. Đừng bắt đầu bằng WebSocket configuration hoặc annotation nếu chưa biết response shape mà client cần; ngược lại, đừng dừng ở query syntax khi use case đã cần transaction, pagination, authorization hoặc event delivery guarantee.

Nội dung nhập môn

Phần nhập môn tập trung vào điều client viết và điều schema cam kết:

  • Selection set, nested field và alias cho biết response có hình dạng nào.
  • Variables, arguments và fragments tách dữ liệu runtime khỏi document và tổ chức selection dùng lại.
  • Input object và payload đưa một mutation từ request đến outcome có cấu trúc.
  • Subscription ở mức operation giúp phân biệt event stream với query lặp lại.

Các ví dụ ở lớp này dùng schema nhỏ, dữ liệu giả định và response mẫu để làm rõ contract. Chúng không thay thế việc kiểm tra schema thật, resolver thật hoặc data source thật.

Bài triển khai chuyên sâu

Phần chuyên sâu tập trung vào các quyết định có thể làm API khó vận hành nếu để muộn:

  • Error contract, null bubbling, retry và idempotency cho mutation.
  • Protocol WebSocket, connection lifecycle, authentication, per-event authorization, fan-out và backpressure cho subscription.
  • Pagination, filtering và sorting cho list lớn, gồm giới hạn chi phí, thứ tự ổn định, cursor/offset và khả năng tiến hóa input.
  • Mapping vào Spring for GraphQL, context, nested resolver, exception handling và data access ở các nhóm chuyên biệt.

Bài con mô tả từng chủ đề riêng thay vì lặp toàn bộ mental model ở đây. Hãy dùng bảng bản đồ bên dưới để chọn đúng độ sâu cho use case hiện tại.

Thứ tự đọc đề xuất

Chặng một đọc và gửi dữ liệu

  1. Đọc Query, selection set và alias để biết object phải mở selection set, scalar là điểm dừng và alias chỉ đổi response key.
  2. Đọc Variables, arguments và fragments để giữ operation ổn định, truyền input có kiểu và dùng selection chung.
  3. Nếu cần đối chiếu với một request HTTP, xem Mô hình request/response và Kiểm thử request bằng curl/Postman.

Chặng hai thiết kế ghi và lỗi

  1. Đọc Mutation và input/payload để tách input với output, chọn payload và đặt boundary cho service.
  2. Đọc Xử lý lỗi trong mutation để đọc data, top-level errors, payload errors, path, nullability và retry policy cùng nhau.
  3. Khi chuyển contract sang Java, đọc Binding arguments và input và Query, mutation và subscription mapping. Đây là bài triển khai, không phải điều kiện để hiểu cú pháp operation.

Chặng ba realtime và collection

  1. Nếu use case cần event, đọc Subscription và WebSocket để hiểu stream, protocol, lifecycle và các giới hạn production trước khi chọn property hoặc client library.
  2. Đọc Pagination để chọn mô hình page, metadata và cách giới hạn list. Nếu cần nối với data layer Spring, xem thêm Cursor và offset pagination với Spring.
  3. Đọc Filtering và sorting sau pagination để thiết kế input filter/sort có thứ tự ổn định và không biến schema thành danh sách argument khó mở rộng.

Nếu ứng dụng chủ yếu là màn hình danh sách, có thể đọc bước 8 và 9 ngay sau bước 2. Nếu ứng dụng cần realtime, giữ bước 7 sau khi đã hiểu variables và selection set; không cần học pagination trước khi viết một subscription đơn giản.

Bản đồ bài học

Mỗi bài dưới đây có một vai trò riêng trong lộ trình. Các mô tả chỉ giúp chọn điểm bắt đầu; hãy đọc bài tương ứng khi cần chi tiết và ví dụ của chủ đề đó.

BàiLớp nội dungVai trò trong lộ trình
Query, selection set và aliasNhập môn contractĐọc schema từ root đến scalar, xây nested selection và dùng alias mà không nhầm response key với field schema.
Variables, arguments và fragmentsNhập môn contractTách giá trị runtime, kiểm tra kiểu input, dùng argument đúng contract và tái sử dụng selection bằng fragment.
Mutation và input/payloadCầu nối sang ghi dữ liệuThiết kế input object, payload, validation, idempotency và boundary giữa resolver với service.
Xử lý lỗi trong mutationChuyên sâu về reliabilityPhân biệt transport/request error, domain error và execution error; đọc partial data, path, null bubbling và retry.
Subscription và WebSocketChuyên sâu về realtimeTheo dõi từ subscription operation đến Publisher, WebSocket protocol, auth, reconnect, fan-out, backpressure và cleanup.
PaginationChuyên sâu về collectionChọn offset hoặc cursor, biểu diễn page metadata và đặt giới hạn cho list khi dữ liệu tăng lên.
Filtering và sortingChuyên sâu về collectionThiết kế input filter/sort typed, kết hợp với pagination và giữ thứ tự kết quả ổn định, dễ giải thích.

Có thể xem Schema và type system như nền contract của bảng này. Nhóm đó giúp bạn quyết định output/input type, enum, list, nullability và module boundary; nhóm hiện tại dùng các quyết định đó để tạo operation cụ thể.

Điểm nối với Spring for GraphQL

Trong một ứng dụng Spring Boot, operation không gọi thẳng vào database. Một mental model triển khai thực dụng là:

SDL và schemaOperation của clientRoot mapping / nested mappingService / use caseRepository / event sourceGraphQL execution result contract parse, validate, coerce bind argument và context authorization, transaction, data policy dữ liệu hoặc event
SDL và schemaOperation của clientRoot mapping / nested mappingService / use caseRepository / event sourceGraphQL execution result contract parse, validate, coerce bind argument và context authorization, transaction, data policy dữ liệu hoặc event
Contract, policy và data source

Các annotation thường xuất hiện ở lớp mapping:

  • @QueryMapping nối root field dưới Query.
  • @MutationMapping nối root field dưới Mutation.
  • @SubscriptionMapping nối root field dưới Subscription, thường trả một Publisher như Flux khi implementation dùng Reactor.
  • @SchemaMapping nối nested field khi property mặc định không đủ.
  • @Argument nhận giá trị argument sau khi GraphQL đã kiểm tra document và variables.

Annotation không tạo field chưa có trong SDL. Nó cũng không thay service để kiểm tra business rule, authorization, transaction, idempotency hoặc giới hạn truy vấn. Với context và lifecycle, xem Context, interceptor và request lifecycle và DataFetcher và GraphQL context. Với lỗi từ resolver, xem Xử lý lỗi tập trung.

Khi đi từ operation đến code, giữ thứ tự: chốt SDL và response shape, viết operation/variables, xác định mapping, rồi mới chọn service, repository, event source và transport. Property WebSocket, kiểu binding Java và API exception resolver phụ thuộc version; không sao chép chúng từ ví dụ tĩnh mà chưa đối chiếu project thật.

Kết quả sau khi hoàn thành

Bạn có thể tự kiểm tra tiến độ bằng các câu hỏi sau:

  • Tôi có thể giải thích vì sao query, mutation và subscription có semantics khác nhau mà không đồng nhất chúng với HTTP method hoặc URL không?
  • Tôi có thể nhìn vào schema để biết field nào cần selection set, argument nào cần variables và fragment nào có type condition phù hợp không?
  • Tôi có thể thiết kế một mutation tách Input và Payload, nêu rõ outcome thành công, lỗi nghiệp vụ, lỗi execution và chính sách retry không?
  • Tôi có thể giải thích một list cần pagination/filtering/sorting ở đâu, và vì sao cursor, offset, page size cùng thứ tự ổn định là các quyết định contract không?
  • Tôi có thể mô tả subscription từ subscribe đến next, complete, reconnect và cleanup, đồng thời nêu điểm kiểm tra auth và event source không?
  • Tôi có biết khi nào cần chuyển sang mapping, binding, context, nested resolver, data access hoặc deployment thay vì cố giải quyết mọi thứ trong operation document không?

Nếu chưa trả lời được câu hỏi nào, quay lại bài tương ứng trong bảng thay vì đọc thêm một bài triển khai không liên quan. Mục tiêu của nhóm là tạo một đường đi rõ từ nhu cầu client đến trách nhiệm server.

Bước tiếp theo

Chọn hướng tiếp theo theo nền tảng hiện tại:

On this page