backend / protocols / 00_api_protocols_comparison.md

API Protocols Comparison — REST, GraphQL, gRPC, SOAP

6 interview angles 5 min read source

API Protocols Comparison — REST, GraphQL, gRPC, SOAP

Four ways to expose APIs. Different eras, different trade-offs. Interviewers commonly ask “when would you pick which?” — knowing what each is good and bad at is more important than knowing every detail.

The headline differences

REST GraphQL gRPC SOAP
Year 2000 (Fielding) 2015 (Facebook) 2015 (Google) 1998 (Microsoft)
Transport HTTP/1.1 or HTTP/2 HTTP (usually POST) HTTP/2 HTTP (also SMTP, TCP)
Payload JSON (usually) JSON Protobuf (binary) XML
Schema OpenAPI (optional) SDL (built-in) .proto (built-in) WSDL (built-in)
Typing weak unless OpenAPI strong strong strong
Browser-native yes yes no (needs gRPC-Web) yes (but heavy)
Streaming SSE / WebSocket on top subscriptions first-class (4 modes) no
Versioning URL or header additive evolution proto evolution WSDL versioning
Discoverability OpenAPI/Swagger introspection reflection (optional) WSDL
Error model HTTP status codes always 200 + errors array gRPC status codes SOAP Fault
Caching HTTP cache (great) bespoke bespoke bespoke
Tooling universal rich (Apollo, Relay) rich (.proto codegen) dated but mature

When to pick which

REST — the default for public-facing HTTP APIs. Universal client support, HTTP caching, easy to understand. The right answer for ~80% of new B2B APIs.

GraphQL — when clients need flexible, varied views of the same data and over-fetching/under-fetching is costing you. Mobile apps with heterogeneous screens; aggregator UIs that combine many services. Cost: server complexity, N+1 risk, weaker HTTP caching.

gRPC — for service-to-service APIs in a controlled environment (microservices inside your VPC, or trusted partners). Tight schemas, fast binary protocol, streaming. Cost: not browser-native, less human-readable for debugging.

SOAP — only when you’re integrating with a system that requires it (legacy enterprise, banking, government). Don’t choose SOAP for new APIs. Use Zeep on the Python side to consume it.

Performance

Rough order at typical payload sizes (CRUD records):

gRPC + Protobuf  ≈ 5–10× more requests/sec than JSON REST
GraphQL          ≈ similar to REST per-request, but fewer round-trips for complex queries
SOAP             ≈ 0.3–0.5× REST (XML parsing overhead)

But network and database usually dominate. The protocol choice rarely is the bottleneck for typical CRUD APIs.

Schema and contract

Contract source Typed clients
REST OpenAPI / hand-written generate from OpenAPI
GraphQL SDL (schema.graphql) generate from SDL
gRPC .proto file generate from .proto
SOAP WSDL generate from WSDL

For all four, the schema is the contract. The difference is how “real” the schema is to the protocol: GraphQL/gRPC/SOAP enforce it at the wire level; REST + OpenAPI is contract-by-convention (the server can violate the OpenAPI doc without the framework noticing).

Wire format

A “get user” response in each:

REST (JSON):

{"id": 42, "name": "Alice", "email": "alice@example.com"}

GraphQL (JSON, but client decides shape):

{"data": {"user": {"name": "Alice"}}}

gRPC (Protobuf binary):

0x08 0x2a 0x12 0x05 0x41 0x6c 0x69 0x63 0x65 ...

SOAP (XML):

<soap:Envelope>
  <soap:Body>
    <GetUserResponse xmlns="...">
      <User><Id>42</Id><Name>Alice</Name></User>
    </GetUserResponse>
  </soap:Body>
</soap:Envelope>

JSON is the universal denominator. Protobuf is fastest. XML is verbose. GraphQL’s payloads are JSON but request-shaped.

How errors work

REST: HTTP status code + JSON body. Convention: 4xx for client errors, 5xx for server. RFC 7807 (Problem Details) standardizes the body shape.

GraphQL: HTTP 200 even on errors. errors array in response. Partial data possible ({"data": {...partial...}, "errors": [...]}).

gRPC: status codes (OK, NOT_FOUND, INVALID_ARGUMENT, etc.) — 16 standardized codes. Returned via HTTP/2 trailers.

SOAP: <soap:Fault> element in the response body. HTTP 500 typically.

Client-server fit

Client REST GraphQL gRPC SOAP
Browser (JS) excellent excellent poor (needs gRPC-Web) poor (heavy)
Mobile (iOS/Android) excellent excellent excellent OK
Server-to-server excellent OK excellent (best) OK
CLI excellent OK OK poor
Embedded / IoT OK poor excellent poor

Browsers can do GraphQL natively (it’s HTTP+JSON), need a proxy/transcoding layer for gRPC, and chew through SOAP at significant cost. For browser-facing APIs: REST or GraphQL.

Combine them

It’s common to mix:

  • REST at the edge, gRPC internally: clients talk REST/JSON; backend microservices talk gRPC.
  • GraphQL gateway in front of REST/gRPC backends: clients get GraphQL flexibility; services stay simple.
  • SOAP adapter to a modern API: wrap a legacy SOAP system behind a REST or GraphQL facade.

The “best protocol” debate is mostly moot — modern stacks use each where it fits.

Interview angle

  • “REST vs GraphQL — when each?” — REST for simple resource-shaped APIs, public-facing, where HTTP caching matters. GraphQL when clients have heterogeneous data needs (mobile + web + partner integrations all hitting the same backend with different views) and over-fetching is real.
  • “REST vs gRPC?” — REST for browser-facing or public-partner APIs (HTTP/JSON, universal). gRPC for service-to-service in a controlled env: binary, streaming, schema-enforced, much faster.
  • “When would you still use SOAP?” — only when a system you must integrate with requires it (banking, legacy enterprise, government). Don’t choose SOAP for new APIs.
  • “GraphQL vs gRPC — both have schemas, both are typed; what’s the diff?” — GraphQL is client-driven query shape over JSON; gRPC is fixed RPC over binary. GraphQL is for flexible read-mostly APIs; gRPC is for fast service-to-service calls with stable interfaces.
  • “Why doesn’t GraphQL cache as well as REST?” — REST URLs are cache keys; GET on /users/42 is cacheable in any HTTP cache. GraphQL almost always uses POST with query in body — same URL for every query, no cache key. You can do persisted queries with GET to recover HTTP caching, but it’s not the default.
  • “How do errors differ between REST and GraphQL?” — REST uses HTTP status codes (4xx/5xx). GraphQL almost always returns 200 with errors array, optionally with partial data. The “always 200” model lets multi-resource queries succeed for some fields while failing others.