Queries, Mutations & Subscriptions vs REST/gRPC
GraphQL operations are Query for a read, Mutation for a write, and Subscription for a product event stream. Map them to REST methods and gRPC shapes, then leave CDN reads, idempotent POST retries, and mesh streams in their own clusters.
- 1Gist
- 2Maps
- 3Q&A
- 4Sandbox
Voice readout needs Web Speech Synthesis in this browser.
Question ladder
L1
What are the three GraphQL operation types?
Answer
Query, mutation, and subscription.
L2
Does the schema stop a query from writing?
Answer
No. Convention and lint rules do. A write hidden on a query breaks caches and audits.
L3
How do mutations differ at runtime?
Answer
Most servers run root mutation fields serially. Query fields may run in parallel.
L4
Why do many GraphQL servers accept POST for a read?
Answer
Selection sets and variables get large. GET still fits a persisted query with a short id.
L5
What belongs on a mutation input?
Answer
One business intent, an input object, a payload, and an idempotency key when retries are possible.
L6
When is a GraphQL subscription the wrong realtime tool?
Answer
Telemetry firehoses and device-scale fan-out. Those belong on a bus or MQTT. Subscriptions fit a dispatcher UI.
L7
Can one graph sit over REST and gRPC?
Answer
Yes. That is the BFF. The leaves keep their own contracts. The graph does not replace them.
Failure modes
Write hidden on a query field
Clients and caches repeat it. The audit trail says it was a read.
God mutation
One field updates everything. Callers cannot tell which side effect ran.
Subscription used as a telemetry pipe
Sticky connections and fan-out fall over. The bus already solved broadcast.
Retry without a key
A timed-out place-order mutation creates a second order.
Misconceptions
Query means the server proved there is no side effect.
It is a convention. Lint it. Do not put writes there.
Subscriptions are required for anything live.
SSE, raw WebSockets, MQTT, or polling can fit better. Pick from the product scale.
GraphQL pagination is a new invention.
Bound every list. Cursor or offset details live in the API Design cluster.
Interviewer traps
Drawing gRPC bidi flow control when asked about subscriptions.
Say internal streams stay in the gRPC cluster. Stay on product events versus firehoses.
Re-deriving cursor page tokens.
Say every list takes a bound, then point at the pagination lesson.
Design scenario
Same prompt for every reader.
Requirements
The home screen is one GraphQL query. The price list stays a cacheable GET. Driver telemetry does not flow through subscriptions. Payment capture stays idempotent.
Traffic / scale
Home screen reads dominate. Live status is thousands of dispatcher clients, not millions of devices.
Latency
The home screen is one client round trip. Payment capture has its own deadline on the RPC.
Consistency
A retried place-order mutation returns the original order.
Availability
If one aggregated service is down, the query returns partial data and an error path for that field.
Failure assumptions
- Someone records a view on a query field.
- Someone subscribes to a high-volume device topic.
Constraints
- Do not move the price file onto the graph.
- Do not re-specify cursor internals.
Prompt
A home screen aggregates six services. Partners download a price list through a CDN. Drivers need live order status. Payments are an internal RPC.
API
Which operation is the home screen, the order write, and the dispatcher stream?
Data
What idempotency key rides on the mutation input?
Architecture
Which hop is GraphQL, which is REST, and which is gRPC?
Overview
| GraphQL | Intent | REST analogue | gRPC analogue |
|---|---|---|---|
| Query | Read, no side effects by convention | GET, sometimes a POST search | Unary read |
| Mutation | Write or other side effect | POST, PUT, PATCH, DELETE | Unary write |
| Subscription | Push a stream of events | SSE or a WebSocket channel | Server stream, sometimes bidi |
The schema will not enforce purity. Lint and review do. A query that charges a card will be cached, retried, and logged as a read.
Flow
- 1
Product clients
- nextGraphQL query BFF
- nextREST for CDN and uploads
- 2
GraphQL query BFF
- nextInternal gRPC services
- 3
Internal gRPC services
- 4
REST for CDN and uploads
Lesson map
Queries, Mutations & Subscriptions vs REST/gRPC
GraphQL operations are Query for a read, Mutation for a write, and Subscription for a product event stream. Map them to REST methods and gRPC shapes, then leave CDN reads, idempotent POST retries, and mesh streams in their own clusters.
Architecture. Architecture
Select a node to see why it exists, or an edge to see the protocol, direction, effect, and consequence.
Mermaid export
flowchart TB a["Product clients"] b["GraphQL query BFF"] c["Internal gRPC services"] d["REST for CDN and uploads"] a -->|Product clients to GraphQL query BFF| b b -->|GraphQL query BFF| c a -->|Product clients to REST for CDN and uploads| d
Web and mobile can share the graph. Assets and simple public CRUD stay on REST so a CDN can cache them. The graph calls gRPC. It does not become the mesh.
Queries
Strengths. One round trip for a nested screen. The selection set is typed. A BFF can aggregate many leaves.
Traps. Unbounded nesting. POST bodies that skip shared caches. Clients in production inventing a new expensive query every release.
Mitigations live mostly in AuthZ and cost limits: persisted queries, allowlists, depth, and cost. Every list still needs a bound. Cursor versus offset is pagination. This page only requires the bound.
Pick the operation
- 1
Read a screen
Query. No writes. Parallel fields are fine. - 2
Change the business
One mutation, one intent, input plus payload. - 3
Retry the write
Client sends an idempotency key. The server returns the original result. - 4
Tell a human UI
Subscription for order status on a dispatcher screen. - 5
Tell a million devices
Not a subscription. Use the bus or MQTT.
Mutations
- One mutation is one business intent.
placeOrder, not a field that updates every table. - Use an input and a payload. The shape is the schema lesson.
- Pass an idempotency key when the client may retry. Storage and replay live in idempotency keys.
- Return enough for the UI to refresh when that is cheap. Do not force a second mega-query if the payload can carry the order.
- Document partial failure:
userErrorson the payload versus a thrown top-level error.
Press Run. Snippets must be self-contained — no network, files, or native modules.
The sketch shows dedupe of the response. It is not the full idempotency design.
Subscriptions versus the other realtime tools
| Approach | Fit | Caution |
|---|---|---|
| GraphQL subscriptions | Product UI events, such as order status | Sticky connections. Fan-out is your problem |
| REST plus SSE | Simple server-to-client streams | One direction. Proxies time out |
| Raw WebSockets | Custom protocols | You own framing and auth refresh |
| gRPC server streaming | Internal pipelines | Not browser-native without a gateway |
| MQTT | IoT and huge topic fan-out | Different model. See the realtime cluster |
Do not use GraphQL subscriptions for telemetry firehoses or multi-million device fan-out. Use them for human-scale product events. Protocol comparison: WebSockets and MQTT. Internal streams: gRPC. Do not re-teach flow control here.
Press Run. Snippets must be self-contained — no network, files, or native modules.
Decision snippets
- Public partner CRUD and a CDN: REST.
- Mobile home screen over six services: a GraphQL query BFF.
- Payment capture between ledgers: gRPC or a REST write with an idempotency key. GraphQL at the edge is fine if it delegates.
- Live map for drivers at IoT scale: a bus or MQTT. A GraphQL subscription only for the dispatcher slice.
Pitfalls
A partner price file, a home screen, and a payment capture. Which is REST, which is a GraphQL query, which stays gRPC? Where does the idempotency key sit?
Interview Q&A
What is the difference between Query and Mutation?
Answer
Conventionally, reads versus writes. Many servers run root mutation fields one after another and may run query fields in parallel. The type system does not prove a query is pure.
Why might GraphQL use HTTP POST for queries?
Answer
Selection sets and variables are large. GET still works for a persisted query identified by a short id, which is also easier to cache.
Are subscriptions required for realtime?
Answer
No. SSE, WebSockets, MQTT, or polling may fit. Subscriptions fit a product graph over a socket. See WebSockets and MQTT.
How does this relate to gRPC streaming?
Answer
gRPC streams are the internal pipe. GraphQL subscriptions are the product UI. Streaming mechanics stay in gRPC and the comparison page.
Can one schema call REST backends?
Answer
Yes. A GraphQL BFF in front of REST and gRPC is the common layout. The leaves keep their contracts.
Why not put side effects in a query?
Answer
Caches, CDNs, and clients assume a query is safe to repeat. Writes belong on mutations so audits and retries have a place to live.
How do you paginate lists?
Answer
Give every list a bound. Connection cursors or limit and offset both work. The algorithm and the cache implications are pagination, filtering, and sorting.
What do you return when a mutation is retried?
Answer
The original success payload for that idempotency key, not a second order. The key's lifecycle is idempotency keys.