API Design and Service Communication: REST vs gRPC vs GraphQL
How services and clients talk to each other: REST (resources over HTTP), gRPC (fast binary RPC) or GraphQL (the client gets exactly the data it asks for).
31.1 Why is it used?
- Good API design lets mobile, web and partners integrate easily and keeps breaking changes low.
- Between microservices every millisecond matters; gRPC gives a payload much smaller and faster than JSON REST.
- If a mobile app must call 5 APIs for one screen, it is slow; GraphQL can fetch everything in one query.
- Duplicate payments on retry, or returning lakhs of records at once: idempotency and pagination solve these.
31.2 How it works
- REST: resources + HTTP verbs (GET /orders/123, POST /orders), status codes (200, 201, 400, 404, 429, 500), JSON body.
- gRPC: the contract lives in Protocol Buffers (.proto), binary over HTTP/2; unary + client/server/bidirectional streaming, code is auto-generated.
- GraphQL: one endpoint (/graphql), schema + typed queries; the client chooses the fields, so over-fetching/under-fetching disappear.
- Versioning: URL (/v1/orders), header (Accept-Version), or backward-compatible changes (only add new optional fields); in GraphQL you deprecate fields.
- Pagination: offset/limit (simple, but deep pages are slow and data shifts); cursor/keyset (next_cursor=last_id, best for big data).
- Idempotency key: the client sends a unique 'Idempotency-Key' header with every POST; the server stores the result and returns the same response on retry (Stripe's pattern).
- Timeouts, retries with backoff and circuit breaker: essential for service-to-service calls so one slow service does not bring everyone down.
- Sync vs async: if you need an immediate answer use REST/gRPC; do the rest asynchronously through events/queues.
- 1.A REST: Mobile app calls GET /v1/users/42, /v1/payments, /v1/rewards; 1 screen = 3 calls; status codes 200 / 201 / 400 / 404 / 429; over/under-fetching
- 2.B gRPC: API server -> Payment service, HTTP/2 + binary protobuf + streaming; code auto-generated from payment.proto; not directly usable from a browser
- 3.C GraphQL: the web dashboard sends one query (user id 42: name, payments last 5, rewards) -> POST /graphql -> resolvers (users, payments, rewards), backed by gRPC calls
- 4.D Payment API: POST /v1/payments + Idempotency-Key 7f3a; the server saves the key as 'processing' in Redis/DB, then gRPC Pay 499 (charged once)
- 5.If the response is lost / times out, the app retries with the same key; the key is found, so the stored response, 201 + paymentId, is returned and there is no double charge
- 6.Pagination: GET /v1/payments?limit=20 -> 20 records + next_cursor; ?cursor=abc fetches the next 20 (better than offset)
REST/GraphQL outside, gRPC + async events inside
31.3 Tools
| Tool | Type | How it is used |
|---|---|---|
| OpenAPI (Swagger) | REST API spec | Write the REST contract in YAML, generate docs and client SDKs. |
| gRPC + Protocol Buffers | RPC framework (Google, CNCF) | Internal microservice calls; you can also expose them to REST clients via Envoy/grpc-gateway. |
| Apollo GraphQL / GraphQL Federation | GraphQL server + gateway | Joins the schemas of multiple services into one supergraph, giving the frontend a single API. |
| AWS AppSync | Managed GraphQL (AWS) | DynamoDB/Lambda resolvers, real-time subscriptions, serverless. |
| Postman | API testing / docs | Collections, automated API tests and mock servers. |
| Kong / AWS API Gateway / Apigee | API Gateway | Versioned routes, auth, rate limit, transformations; placed in front of public APIs. |
31.4 Comparison: REST vs gRPC vs GraphQL
| Point | REST | gRPC | GraphQL |
|---|---|---|---|
| Format | JSON (text) over HTTP/1.1 or 2 | Protobuf (binary) over HTTP/2 | JSON over HTTP, mostly one endpoint |
| Speed | Good, but larger payload | Fastest, small payload, multiplexing | Good, but complex queries are heavy on the server |
| Contract | Optional (OpenAPI) | Strict .proto, code generation | Strictly typed schema |
| Data fetching | Fixed response, over/under fetching | Fixed per RPC method | The client asks for exact fields |
| Streaming | No (SSE/WebSocket are separate) | Built-in bidirectional streaming | Subscriptions (over WebSocket) |
| Browser support | Native, everywhere | Not direct, needs gRPC-Web + a proxy | Native |
| Caching | HTTP caching is easy (GET, CDN) | Hard | Hard (POST), better with persisted queries |
| Best for | Public APIs, simple CRUD | Internal microservice calls, low latency | Mobile/web frontends with complex screens |
31.5 When to choose which
- REST: public/partner APIs, simple CRUD, when you need CDN caching.
- gRPC: internal service-to-service calls where latency and throughput are critical, or when you need streaming.
- GraphQL: when the frontend needs data from multiple services in one call and screens change quickly.
- Common pattern: REST/GraphQL outside, gRPC + async events inside.
31.6 Real-world example
Scenario: Payment API with idempotency and pagination
- The mobile app taps 'Pay 499': POST /v1/payments with header Idempotency-Key: 7f3a-uuid.
- The API server checks the key in Redis/DB; it is new, so it saves status 'processing' and makes a gRPC call to the payment service.
- Because of a network timeout the app did not get the response, and retries with the same key.
- The server already has the key, so it does not charge again; it returns the stored response (201, paymentId). No double charge.
- The user opens transaction history: GET /v1/payments?limit=20 -> 20 records + next_cursor; on scroll, ?cursor=abc fetches the next 20.
- A new field 'upi_app' is added; it is optional, so old clients do not break and no v2 is needed.
- The web dashboard uses GraphQL to get user + last 5 payments + rewards in one query; in the backend this resolves into gRPC calls.
31.7 Interview tips
- A POST payment API without an idempotency key: a mobile retry causes a double charge.
- Offset pagination on big tables (OFFSET 1000000): the DB gets slow; use cursor-based.
- A breaking change without versioning: a field was renamed and old app versions crash.
- Interview tip: say 'REST for public, gRPC for internal, GraphQL for aggregation', with reasons.