gRPC, GraphQL & Realtime
RPC and realtime transports an analyst chooses between — gRPC and Protobuf, GraphQL vs REST, WebSocket/SSE/long-polling, webhooks and their security, and correlation IDs.
13 questions
JuniorTheoryVery commonWhat is polling, what is long polling, and what does each cost the server?
What is polling, what is long polling, and what does each cost the server?
Polling means the client re-requests new data on a fixed interval; most responses are empty, wasting requests and adding up to one interval of latency. Long polling holds each request open until data or a timeout, then reopens. That removes the empty round-trips but ties up a connection per waiting client.
Common mistakes
- ✗Confusing which one holds the request open (long polling) versus fires on a timer (polling)
- ✗Assuming polling is free — empty responses still cost requests and latency
- ✗Forgetting long polling ties up a server connection per waiting client
Follow-up questions
- →When does long polling stop scaling, and what replaces it?
- →How do you pick the polling interval against freshness and load?
JuniorTheoryVery commonWhat is a webhook, and what are its main advantages and drawbacks versus polling?
What is a webhook, and what are its main advantages and drawbacks versus polling?
A webhook is a reverse API call: instead of you polling it, a provider sends an HTTP POST to a URL you registered when an event fires. The advantage is push efficiency — data arrives immediately with no wasted requests. The drawbacks: you must host a public, secured endpoint and handle missed or duplicate deliveries yourself.
Common mistakes
- ✗Thinking a webhook is the client polling faster, not the provider pushing to you
- ✗Assuming delivery is guaranteed, so no retry or reconciliation is needed
- ✗Forgetting a webhook requires a public, secured, always-available endpoint
Follow-up questions
- →How would you secure a webhook endpoint against forged calls?
- →What do you do when a webhook is never delivered?
MiddleTheoryVery commonWhat is a WebSocket, how is the connection established, and when do you actually need one?
What is a WebSocket, how is the connection established, and when do you actually need one?
A WebSocket is a persistent, full-duplex connection over one TCP socket where both sides push messages anytime. It starts as an HTTP request with an Upgrade: websocket header; if the server agrees, the connection switches protocols. Use it for bidirectional low-latency traffic like chat, not one-way updates.
Common mistakes
- ✗Thinking a WebSocket is one-way rather than full-duplex
- ✗Believing it opens a new connection per message instead of staying persistent
- ✗Reaching for a WebSocket when a one-way SSE or polling would do
Follow-up questions
- →How does the HTTP Upgrade handshake switch protocols on one connection?
- →Why prefer SSE over a WebSocket for server-only updates?
JuniorTheoryCommonWhat is a remote procedure call (RPC), and how does it differ from REST at the contract level?
What is a remote procedure call (RPC), and how does it differ from REST at the contract level?
RPC makes a remote call look like a local function call: the client invokes a named operation like getUser with arguments; the transport is hidden. REST exposes resources at URLs via HTTP verbs. An RPC contract lists methods and parameters; a REST contract lists resources and verbs.
Common mistakes
- ✗Thinking RPC and REST differ only in transport or encryption, not in contract shape
- ✗Believing REST exposes methods while RPC exposes resources (it is the reverse)
- ✗Assuming a remote procedure call cannot cross a network
Follow-up questions
- →When would an RPC-style API be a better fit than REST?
- →How does gRPC build on the basic RPC model?
MiddleTheoryCommonWhat is GraphQL, which REST problems does it solve, and what does it cost you — the N+1 query problem and caching?
What is GraphQL, which REST problems does it solve, and what does it cost you — the N+1 query problem and caching?
GraphQL is a query language with one endpoint and a typed schema: the client asks for exactly the fields it needs. That solves REST's over-fetching and under-fetching. Its costs: per-URL HTTP caching breaks since everything hits one endpoint, and a naive resolver hits the N+1 problem, so you add batching.
Common mistakes
- ✗Thinking GraphQL uses many URLs like REST rather than one endpoint
- ✗Believing GraphQL improves per-URL HTTP caching instead of complicating it
- ✗Assuming the N+1 problem disappears on its own without batching
Follow-up questions
- →How does a dataloader batch resolver calls to fight the N+1 problem?
- →Why is HTTP caching harder with a single GraphQL endpoint?
MiddleTheoryCommonWhat are Server-Sent Events (SSE), and how do they differ from a WebSocket and from long polling?
What are Server-Sent Events (SSE), and how do they differ from a WebSocket and from long polling?
SSE is a one-way stream: the client opens a long-lived HTTP connection and the server pushes text events, auto-reconnecting. Unlike a WebSocket it is server-to-client only over plain HTTP, so simpler and proxy-friendly. Unlike long polling it holds the connection open, not reopening each message.
Common mistakes
- ✗Thinking SSE is bidirectional like a WebSocket rather than server-to-client only
- ✗Believing SSE needs a non-HTTP protocol or port
- ✗Forgetting SSE reconnects automatically, unlike hand-rolled long polling
Follow-up questions
- →Why is SSE more proxy-friendly than a WebSocket?
- →When does a one-way SSE stream stop being enough?
MiddleTheoryCommonWhich transport would you choose for a chat, for a stock ticker, and for a bank-to-bank transfer — and why?
Which transport would you choose for a chat, for a stock ticker, and for a bank-to-bank transfer — and why?
Chat needs a WebSocket — both sides send messages continuously, so full-duplex fits. A ticker is one-way high-frequency push, so SSE or a WebSocket fits. A bank-to-bank transfer isn't real-time — a single reliable, idempotent, auditable operation, so a request/response or queued message fits, not a socket.
Common mistakes
- ✗Forcing one transport onto all three instead of matching direction and guarantees
- ✗Treating a bank transfer as streaming rather than a reliable single operation
- ✗Confusing the one-way ticker feed with bidirectional chat
Follow-up questions
- →Why does a transfer favor idempotency over low latency?
- →When would you move the ticker feed from SSE to a WebSocket?
MiddleDesignCommonYour system exposes a public webhook endpoint that a payment provider calls on every transaction. Describe how you would secure this endpoint so a forged or replayed request cannot trigger a fake payment event, and describe what your system must do when a legitimate webhook never arrives — for example the provider's delivery times out or your endpoint is briefly down. Cover both the authentication of an incoming call and the recovery of a missed one.
Your system exposes a public webhook endpoint that a payment provider calls on every transaction. Describe how you would secure this endpoint so a forged or replayed request cannot trigger a fake payment event, and describe what your system must do when a legitimate webhook never arrives — for example the provider's delivery times out or your endpoint is briefly down. Cover both the authentication of an incoming call and the recovery of a missed one.
Verify a signature: the provider signs the body with a shared secret (HMAC) that you recompute and compare, rejecting failures. Add a timestamp or nonce check against replays, and accept only HTTPS. For missed deliveries, don't treat the webhook as the only path — make handlers idempotent and reconcile by polling the provider's API.
Common mistakes
- ✗Trusting a secret URL or source IP instead of verifying a signature
- ✗Assuming delivery is guaranteed, so no reconciliation is needed
- ✗Skipping idempotency, so a provider retry double-processes the event
Follow-up questions
- →How does a timestamp or nonce stop a captured request from being replayed?
- →Why must the webhook handler be idempotent for retries to be safe?
MiddleTheoryOccasionalWhat is a correlation ID, who generates it, and how does it travel across a mixed sync and async chain?
What is a correlation ID, who generates it, and how does it travel across a mixed sync and async chain?
A correlation ID is a token on a request that ties every log line and hop of one operation across services. It is generated once at the entry point — the gateway or first service — if the caller didn't supply one. It rides an HTTP header on sync calls and message metadata on async, unchanged by each service.
Common mistakes
- ✗Thinking each service generates its own ID instead of propagating one unchanged
- ✗Assuming it works only on synchronous calls, not across async messages
- ✗Generating it at the end of the flow rather than at the entry point
Follow-up questions
- →How does a correlation ID cross a message queue boundary?
- →How does it differ from a per-hop span ID in distributed tracing?
MiddleTheoryOccasionalWhat is gRPC, what transport and contract does it use, and when does it beat REST?
What is gRPC, what transport and contract does it use, and when does it beat REST?
gRPC is Google's RPC framework over HTTP/2, encoding messages with Protobuf under a strict .proto contract. HTTP/2 gives multiplexing and streaming; Protobuf gives a compact binary payload and generated stubs. It beats REST for high-volume backend-to-backend calls; REST suits public browser APIs.
Common mistakes
- ✗Thinking gRPC sends JSON or XML rather than binary Protobuf
- ✗Believing gRPC is browser-native and best for public web APIs
- ✗Forgetting the
.protocontract generates the client and server stubs
Follow-up questions
- →Why does gRPC need HTTP/2 rather than HTTP/1.1?
- →What makes gRPC awkward to call directly from a browser?
MiddleTheoryOccasionalWhat is Protobuf, how does it differ from JSON on the wire, and what does the .proto contract give you?
What is Protobuf, how does it differ from JSON on the wire, and what does the .proto contract give you?
Protobuf is a binary serialization format. It sends compact tagged bytes, not JSON's readable text, so payloads are smaller and faster but unreadable without the schema. The .proto file defines tagged fields and generates code; sides evolve independently as long as tags aren't reused.
Common mistakes
- ✗Thinking Protobuf is readable text like JSON rather than tagged binary
- ✗Believing Protobuf payloads are larger or slower than JSON
- ✗Reusing or renumbering field tags, which silently breaks the contract
Follow-up questions
- →How does a field's numeric tag enable backward-compatible evolution?
- →When is JSON still the better choice over Protobuf?
SeniorDesignRareA mobile screen currently makes 12 separate REST calls to render, which is slow on a phone network. Three options are on the table: expose a GraphQL endpoint, build a Backend-for-Frontend (BFF) service that the app calls once, or add a REST aggregate endpoint that composes the 12 calls server-side. Argue which you would choose and why, considering the number of round-trips over mobile latency, who owns the composition logic, caching, and how many different client types you must serve.
A mobile screen currently makes 12 separate REST calls to render, which is slow on a phone network. Three options are on the table: expose a GraphQL endpoint, build a Backend-for-Frontend (BFF) service that the app calls once, or add a REST aggregate endpoint that composes the 12 calls server-side. Argue which you would choose and why, considering the number of round-trips over mobile latency, who owns the composition logic, caching, and how many different client types you must serve.
All three collapse the 12 round-trips into one, so choose by ownership and client count. A REST aggregate suits one screen with a fixed payload. A BFF fits when the app needs its own evolving shape owned by its team. GraphQL fits when many client types each need different fields. The trade-off is added composition and weaker caching.
Common mistakes
- ✗Treating GraphQL, a BFF, and a REST aggregate as interchangeable with no trade-offs
- ✗Assuming one BFF should serve every client type at once
- ✗Believing aggregation improves per-URL caching rather than weakening it
Follow-up questions
- →When does a BFF become a better fit than GraphQL for one app?
- →Why does collapsing round-trips matter more on a mobile network?
SeniorDesignRareAn order-status change must reach three consumers: a web client that has the order page open, a customer's mobile app that may be backgrounded or offline, and a partner company's backend system. For each of the three, choose a delivery transport — for example a WebSocket or SSE, a push notification, a webhook, or polling — and justify the choice against that consumer's connectivity, its latency needs, and who controls the endpoint. Explain why one single transport cannot serve all three well.
An order-status change must reach three consumers: a web client that has the order page open, a customer's mobile app that may be backgrounded or offline, and a partner company's backend system. For each of the three, choose a delivery transport — for example a WebSocket or SSE, a push notification, a webhook, or polling — and justify the choice against that consumer's connectivity, its latency needs, and who controls the endpoint. Explain why one single transport cannot serve all three well.
Use SSE or a WebSocket for the open web page. Use a platform push for the mobile app, often backgrounded or offline and unable to hold a socket. Use a webhook — a server callback — for the partner backend, which owns a public endpoint. One transport can't serve all three: connectivity, endpoint ownership, and delay tolerance differ.
Common mistakes
- ✗Forcing one transport onto all three consumers with different connectivity
- ✗Expecting a backgrounded or offline app to hold a live socket
- ✗Giving a browser or phone a webhook endpoint the server can call
Follow-up questions
- →Why can't a backgrounded mobile app rely on a held-open socket?
- →What makes a webhook the natural fit for a partner backend?