Mutations & When to Choose GraphQL
Changing data with mutations, a word on subscriptions, and a clear-eyed verdict on when GraphQL is worth it versus a REST API.
On this page
Queries read; mutations write. GraphQL keeps them separate so intent is explicit and the engine can treat them differently. This final lesson covers writing data with mutations, a brief word on subscriptions, and - most importantly - an honest verdict on when GraphQL is worth it versus a plain REST API, because "we should use GraphQL" is a decision, not a default.
Mutations: changing data
A mutation is a root-type field under Mutation, resolved with @MutationMapping. It takes arguments, performs
the write, and returns the affected object so the client gets fresh data in the same round-trip:
type Mutation {
borrowBook(bookId: ID!, memberId: ID!): Loan!
}@Controller
class LoanController {
@MutationMapping
Loan borrowBook(@Argument Long bookId, @Argument Long memberId) {
return loanService.borrow(bookId, memberId); // create the loan, return it
}
}The client calls it and asks for exactly the fields it wants back:
mutation {
borrowBook(bookId: 42, memberId: 7) {
id
dueDate
book { title } # traverse the result like any query
}
}Two conventions matter. Queries may run in parallel; mutations in a single request run sequentially, top to bottom - so writes have predictable order. And a mutation returns the mutated entity (or a richer payload type) so the client can refresh its cache without a second query.
Validation and errors
Mutations are where bad input arrives, so validate. Bean Validation (@Valid on an @Argument input type) works, and you signal domain failures by throwing an exception mapped to a GraphQL error via a DataFetcherExceptionResolver. GraphQL responses can carry both data and an errors array - a partial success is normal, so design your error handling around that rather than HTTP status codes.
A word on subscriptions
The third root type, Subscription, streams updates to the client over a persistent connection (typically
WebSocket) - e.g. "notify me when a book I reserved becomes available". Spring for GraphQL supports it via
reactive Flux return types. It's powerful but adds a stateful transport; adopt it only when you genuinely need
server-push, not for ordinary reads.
The honest verdict: GraphQL or REST?
GraphQL is a tool with a real cost. Choose it deliberately.
Reach for GraphQL when:
- Diverse clients shape their own data - a mobile app wanting minimal fields and a web app wanting rich detail hit one endpoint without you building bespoke variants.
- Rich, connected data where screens stitch many related resources (the book + author + reviews + loan status case) - one query beats six REST round-trips.
- A fast-moving frontend benefits from adding fields without new backend endpoints.
Stay with REST when:
- The API is simple and stable - CRUD over a few resources doesn't need a query language.
- HTTP caching matters - REST's cacheable
GETs are a huge, near-free win GraphQL sacrifices. - The consumers are server-to-server with fixed, known needs - the client-shapes-the-response benefit is moot.
- File uploads, streaming, or simple public APIs - REST is the well-trodden path.
Plenty of systems use both: REST for stable public/CRUD endpoints and internal service calls, GraphQL as a mobile/BFF (backend-for-frontend) aggregation layer over them. For BookVault, adding a single GraphQL catalog endpoint alongside the existing REST API is a reasonable way to serve a data-hungry mobile client without tearing out what works.
GraphQL is a Swiss Army knife - astonishingly flexible, one tool your varied clients each fold open to exactly the blade they need. REST is a chef's knife - simpler, superbly sharp at the one job, and what you grab for routine work. You don't bring the multi-tool to dice an onion (a stable CRUD endpoint), and you don't whittle a custom REST endpoint for every screen a mobile team dreams up (that's the multi-tool's moment). Mature kitchens own both and know which to reach for.
Three teams ask your advice. (a) An internal billing service needs to read invoices from an accounting service, same fields every time. (b) A new React Native app must render dashboards stitching users, orders, products, and recommendations. (c) A public webhook endpoint other companies POST events to. For each, GraphQL or REST - and why?
When is GraphQL most clearly the right choice over REST?
Key takeaways
- Mutations are Mutation-type fields resolved with @MutationMapping; they take arguments, perform the write, and return the affected object for the same round-trip.
- Queries can run in parallel but mutations in one request run sequentially; validate mutation input and map domain failures to GraphQL errors.
- Subscriptions stream server-push updates over WebSocket via reactive Flux - powerful but stateful; use only when you need push.
- Choose GraphQL for diverse clients shaping their own data and rich connected data stitched in one query; choose REST for simple/stable APIs, HTTP caching, and fixed server-to-server needs.
- Many systems use both - REST for stable/public/CRUD and GraphQL as a mobile/BFF aggregation layer; a single GraphQL catalog endpoint on BookVault is a sensible, incremental adoption.