---
title: "04 — Different API Styles: REST, gRPC, GraphQL, SOAP"
uid: api-design-api-styles
tags: ["grpc", "rest", "architecture", "soap", "roadmap:api-design", "api", "graphql"]
excerpt: "REST, SOAP, gRPC, GraphQL: not interchangeable flavors of the same thing. Each style is a different answer to one question — how client and server agree on the shape of a conversation — optimized for a different constraint."
date: 2026-08-13T03:28:34+0000
source: https://www.aveshina.my.id/en/blog/api-design-api-styles
---

Choosing between REST, SOAP, gRPC, and GraphQL used to feel like picking a favorite flavor — until I saw them as different answers to one question. The frame that finally clicked: **every style is a different answer to the same question, "how do client and server agree on the shape of the conversation," and the right choice depends on who the client is and how varied their needs are.** [1] The technologies are not interchangeable flavors of the same thing; each one optimizes for a different constraint.

The framing I use now is a tradeoff matrix. REST optimizes for simplicity and HTTP-friendliness. SOAP optimizes for contract strictness and enterprise tooling. gRPC optimizes for service-to-service performance. GraphQL optimizes for client flexibility when clients are varied. Picking a style is really picking which of those constraints hurts the most.

```figure
<svg viewBox="0 0 740 280" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="Four API styles compared on a 2D plot. Horizontal axis: from rigid/server-decided shape on the left to flexible/client-declared shape on the right. Vertical axis: from human-readable text at the bottom to binary/compact at the top. SOAP sits bottom-left (rigid, text). REST sits center-bottom (medium, text/JSON). gRPC sits top-center (binary, server schema). GraphQL sits bottom-right (flexible, client-declared).">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">
    <!-- axes -->
    <line x1="80" y1="240" x2="700" y2="240" stroke="#475569" stroke-width="1.5"/>
    <line x1="80" y1="40" x2="80" y2="240" stroke="#475569" stroke-width="1.5"/>
    <text x="390" y="265" font-size="11" font-weight="700" fill="#475569" text-anchor="middle">shape: server-decided  →  client-declared</text>
    <text x="40" y="140" font-size="11" font-weight="700" fill="#475569" text-anchor="middle" transform="rotate(-90 40 140)">binary  ↑  /  ↓  text</text>

    <!-- SOAP (rigid, text) -->
    <circle cx="180" cy="200" r="34" fill="#fee2e2" stroke="#dc2626" stroke-width="2"/>
    <text x="180" y="198" font-size="12" font-weight="700" fill="#7f1d1d" text-anchor="middle">SOAP</text>
    <text x="180" y="213" font-size="9" fill="#7f1d1d" text-anchor="middle">XML envelope</text>

    <!-- gRPC (binary, server schema) -->
    <circle cx="400" cy="90" r="34" fill="#e0e7ff" stroke="#6366f1" stroke-width="2"/>
    <text x="400" y="88" font-size="12" font-weight="700" fill="#1e1b4b" text-anchor="middle">gRPC</text>
    <text x="400" y="103" font-size="9" fill="#1e1b4b" text-anchor="middle">binary + HTTP/2</text>

    <!-- REST (medium, text) -->
    <circle cx="400" cy="195" r="34" fill="#dcfce7" stroke="#16a34a" stroke-width="2"/>
    <text x="400" y="193" font-size="12" font-weight="700" fill="#052e16" text-anchor="middle">REST</text>
    <text x="400" y="208" font-size="9" fill="#052e16" text-anchor="middle">JSON + HTTP</text>

    <!-- GraphQL (flexible, text) -->
    <circle cx="620" cy="195" r="34" fill="#fce7f3" stroke="#db2777" stroke-width="2"/>
    <text x="620" y="193" font-size="12" font-weight="700" fill="#500724" text-anchor="middle">GraphQL</text>
    <text x="620" y="208" font-size="9" fill="#500724" text-anchor="middle">typed graph</text>
  </g>
</svg>
```

## REST: resources over HTTP

**REST** (Representational State Transfer) is the default most teams reach for, and its core idea is *model the API as resources, manipulate them with HTTP verbs.* [2][3] A resource is a noun — /orders, /users/42 — and the verbs (GET, POST, PUT, DELETE) describe what you're doing to it. The contract is the URL plus the method; the body is the resource's representation, usually JSON.

REST's defining constraints are what make it feel "webby": **stateless** (each request is self-contained), **client-server** separation (the client and server each mind their own concerns), **cacheable** responses, and a **uniform interface** (every resource is addressed the same way) [2]. The payoff is that REST rides HTTP so naturally that browsers, caches, proxies, and curl all understand it without special tooling. The cost is the fixed-shape problem — one GET /users/42 returns one shape for every client, which over-fetches for the mobile chip and under-fetches for the dashboard.

A note on **HATEOAS** (Hypermedia As The Engine Of Application State): it's a REST ideal where responses include links to the next valid actions, so a client can navigate the API dynamically like a human browses web pages [4]. In theory it makes APIs self-describing. In practice almost no one implements it fully — the industry settled on "REST without HATEOAS" because static, documented JSON endpoints are easier to build and consume. I treat HATEOAS as a known ideal, not a daily reality.

## SOAP: the strict envelope

**SOAP** (Simple Object Access Protocol) is the enterprise predecessor to REST. It wraps every message in a standardized XML **envelope** with a header and body, and it carries its contract in a WSDL file (a machine-readable description of the service) that tooling can use to generate clients in any language [5]. SOAP is rigid, verbose, and opinionated — and that's exactly its appeal in the domains that still use it (payments, banking, legacy enterprise).

```
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Body>
    <GetOrder><orderId>42</orderId></GetOrder>
  </soap:Body>
</soap:Envelope>
```

The model I hold for SOAP: it trades simplicity for **reliability and built-in WS-\* standards** — security, transactions, messaging guarantees that REST leaves you to assemble yourself. If you're not in a regulated/legacy context that demands it, SOAP's XML overhead and WSDL complexity are usually not worth it. New greenfield APIs rarely choose SOAP, but reading it is still a job skill because so much legacy infrastructure speaks it.

## gRPC: binary, fast, service-to-service

**gRPC** is Google's modern RPC framework, and it's built for a different audience than REST — *other services*, not browsers [6]. The contract is a **Protocol Buffers** idl file (Google's format for describing services and messages); the protoc compiler generates typed clients and servers in many languages. The wire format is **binary and compact**, and the transport is **HTTP/2**, which gives gRPC its standout feature: **bidirectional streaming**.

```
service Orders {
  rpc GetOrder (OrderRequest) returns (Order);
  rpc StreamUpdates (OrderRequest) returns (stream OrderUpdate);
}
```

The tradeoff is clear-eyed. gRPC is dramatically faster and more compact than JSON-over-HTTP, and the generated typed clients catch contract violations at compile time (before the code even runs). But browsers can't speak gRPC directly without a gateway (gRPC-Web), and the binary wire format is unreadable to humans without tooling. **The right use case is internal service-to-service calls** where both sides are machines, performance matters, and the proto contract is the source of truth. gRPC is the wrong default for a public-facing API consumed by browser apps.

## GraphQL: the client declares the shape

**GraphQL** flips the authority: instead of the server exposing fixed endpoints, it exposes *one* endpoint holding a typed graph of everything, and the client writes a query describing exactly the shape it wants back [7]. No over-fetching, no under-fetching, one round trip for nested data. The schema is a strongly typed contract, validated on both sides.

I won't re-derive GraphQL here — there's a whole post on it in this series. The style-relevant point is *when* GraphQL earns its complexity: when clients are varied (a mobile chip wanting two fields and a dashboard wanting forty, all from the same entity) and when screens need nested data across what would be multiple REST round trips. If clients are uniform and shapes are stable, REST is simpler and GraphQL's resolver/auth/governance overhead isn't worth it.

## JSON: the common currency

Underneath REST, GraphQL, and even SOAP (as a transport alternative) sits **JSON** — JavaScript Object Notation — as the dominant data format [8]. JSON won because it's lightweight, human-readable, and native to every browser. There's even a formal **JSON:API** specification that standardizes how JSON APIs should structure responses, errors, and relationships [8]. Most teams don't adopt the full JSON:API spec, but the principles it encodes — consistent resource objects, conventional error shapes, sideloaded relationships — are good defaults to steal.

## How I use this

The decision is a checklist, not a preference. Is the API consumed by browsers and third parties? REST (or GraphQL if clients are wildly varied). Is it internal service-to-service, performance-sensitive, with polyglot services? gRPC. Is it a regulated/legacy enterprise context with existing SOAP investment? Stay SOAP. GraphQL specifically when over-fetching or multiple round trips are hurting real clients. The mistake I try to avoid is reaching for the newest style by default — gRPC in a browser-facing API, or GraphQL where a single REST endpoint would do. Each style is an optimization for a specific constraint; the work is identifying which constraint is actually yours.

## References

[1] Red Hat, "API styles," 2024. [Online]. Available: [https://www.redhat.com/architect/api-styles](https://www.redhat.com/architect/api-styles)

[2] DreamFactory, "REST API Principles | A Comprehensive Overview," 2024. [Online]. Available: [https://blog.dreamfactory.com/rest-apis-an-overview-of-basic-principles](https://blog.dreamfactory.com/rest-apis-an-overview-of-basic-principles)

[3] Amazon Web Services, "What is a RESTful API?," 2024. [Online]. Available: [https://aws.amazon.com/what-is/restful-api/](https://aws.amazon.com/what-is/restful-api/)

[4] restfulapi.net, "HATEOAS Driven REST APIs," 2024. [Online]. Available: [https://restfulapi.net/hateoas/](https://restfulapi.net/hateoas/)

[5] SoapUI, "SOAP vs REST 101: Understand The Differences," 2024. [Online]. Available: [https://www.soapui.org/learn/api/soap-vs-rest-api/](https://www.soapui.org/learn/api/soap-vs-rest-api/)

[6] gRPC Authors, "Introduction to gRPC," grpc.io, 2024. [Online]. Available: [https://grpc.io/docs/what-is-grpc/introduction/](https://grpc.io/docs/what-is-grpc/introduction/)

[7] GraphQL Foundation, "GraphQL," 2024. [Online]. Available: [https://graphql.org/](https://graphql.org/)

[8] JSON:API, "Specification for Building JSON APIs," GitHub, 2024. [Online]. Available: [https://github.com/json-api/json-api](https://github.com/json-api/json-api)

```quiz
Q: Which API style is best suited to high-performance, internal, service-to-service calls?
- SOAP
- gRPC
- REST without streaming
correct: 1
explain: gRPC uses compact binary Protocol Buffers over HTTP/2 with bidirectional streaming, and generates typed clients. It's tuned for machine-to-machine performance; browsers can't speak it directly.

Q: What does HATEOAS propose that REST responses should include?
- Links to the next valid actions, so clients can navigate the API dynamically
- The full database schema
correct: 0
explain: HATEOAS (Hypermedia As The Engine Of Application State) wants responses to carry hyperlinks to valid next steps. It's a REST ideal rarely fully implemented in practice.

Q: A public API will be consumed by many different clients — a mobile app, a dashboard, third-party scripts — each wanting different slices of the same data. Which style most directly addresses over- and under-fetching?
- GraphQL
- SOAP
correct: 0
explain: GraphQL lets each client declare exactly the fields it needs from one typed graph, which solves over- and under-fetching when clients are varied.

Q: SOAP's main appeal in the domains that still use it is…
- built-in WS-* standards (security, transactions, messaging) and a strict WSDL contract
- being faster than gRPC
correct: 0
explain: SOAP trades verbosity and complexity for reliability and standardized enterprise tooling. It's not chosen for speed.

Q: REST's "stateless" constraint means…
- the server keeps no memory between requests; each request is self-contained
- the API has no authentication
correct: 0
explain: Stateless means each request carries everything the server needs. Sessions, cookies, and tokens are workarounds layered on top to fake persistence.
```
