About this article
This article is the fourth deep dive in the “Software Architecture” category of the Architecture Crash Course for the Generative-AI Era series, covering API design.
“A published API is a contract.” Naming, data shape, errors, auth — all become things consumers depend on, so you can’t change them lightly later. The article compares the four major styles (REST / GraphQL / gRPC / WebSocket), use-case selection, versioning strategy, auth methods, and rate-limit numerical baselines.
What is an API in the first place
An API is, in a nutshell, “a window through which software talks to other software.”
Imagine a restaurant counter. The customer (frontend) looks at the menu (API documentation) and places an order; the kitchen (backend) returns the dish in a fixed vessel (response format). Orders not on the menu are rejected, and if the vessel’s shape suddenly changes the customer is confused — this “set of rules for placing and receiving orders” is an API. Web apps, mobile apps, internal-system integrations, AI invocations — modern software is connected through APIs.
Why API design matters
What happens if API design is sloppy? The moment you publish a “works-for-now endpoint,” external consumers start depending on its shape. URL and parameter naming, data format, error responses, authentication — a published API becomes a contract. Breaking changes force every consumer to adapt — practically impossible to push.
In 2023, when X (formerly Twitter) effectively monetized API v1.1 essentially overnight, classic third-party clients like Tweetbot all stopped at once. The case is remembered as the most violent demonstration of “APIs are contracts.” From the provider side, weak versioning strategy or sunsetting policies destroy consumer trust instantly.
Even URL and parameter naming, the moment you publish them, the backward-compatibility chain locks in. Initial-design quality casts a long shadow.
The moment you publish, it becomes a contract
URL and parameter naming, data shape, error responses, authentication — “a published API is a contract.” External consumers depend on the shape, so it can’t be changed lightly later. Breaking changes force every consumer to adapt — practically impossible to push.
In 2023, when X (formerly Twitter) effectively monetized API v1.1 essentially overnight, classic third-party clients like Tweetbot all stopped at once. The case is remembered as the most violent demonstration of “APIs are contracts.” From the provider side, weak versioning strategy or sunsetting policies destroy consumer trust instantly.
Even URL and parameter naming, the moment you publish them, the backward-compatibility chain locks in. Initial-design quality casts a long shadow.
The four major styles
API design has four major styles. There’s no overall ranking — pick by use. External public APIs and internal microservice traffic require very different traits.
flowchart TB
Q{Use?} -->|External public Web API| REST[REST<br/>HTTP+JSON]
Q -->|Many client kinds<br/>avoid over-fetching| GQL[GraphQL<br/>HTTP+query language]
Q -->|Microservice-to-microservice<br/>internal high-speed| GRPC[gRPC<br/>HTTP/2+Protobuf]
Q -->|Bidirectional real-time| WS[WebSocket<br/>TCP duplex]
REST -.- E1[Most adopted<br/>cacheable]
GQL -.- E2[Facebook 2015<br/>fits BFF]
GRPC -.- E3[Google origin<br/>low latency]
WS -.- E4[Chat / notifications /<br/>stock streams]
classDef question fill:#fef3c7,stroke:#d97706;
classDef rest fill:#dbeafe,stroke:#2563eb;
classDef gql fill:#fae8ff,stroke:#a21caf;
classDef grpc fill:#dcfce7,stroke:#16a34a;
classDef ws fill:#f0f9ff,stroke:#0369a1;
class Q question;
class REST rest;
class GQL gql;
class GRPC grpc;
class WS ws;
| Style | Transport | Typical use |
|---|---|---|
| REST | HTTP + JSON | General Web APIs, external publication |
| GraphQL | HTTP + query language | APIs facing diverse clients |
| gRPC | HTTP/2 + Protobuf | Microservice-to-microservice internal traffic |
| WebSocket | TCP duplex | Real-time communication |
Real projects often combine multiple — “REST + some WebSocket” is common.
Quick decision flow
Before details, the first candidate per use case. Pin the answer here, then check details.
| Use | First choice | Second |
|---|---|---|
| Public API (for developers) | REST | — |
| Internal microservice traffic | gRPC | REST |
| API for screens used by Web and Mobile | GraphQL or BFF + REST | REST |
| Chat, games, stock-price streaming | WebSocket | Server-Sent Events |
| TypeScript single-stack (Next.js, etc.) | tRPC (type sharing) | REST |
| Integration with existing public-sector / financial assets | REST or SOAP | gRPC |
For external publication, REST is the default; the burden of proof is reasons to pick anything else.
REST
REST (Representational State Transfer) is a resource-oriented API style using HTTP’s standard features as-is. URLs name resources (/users/123); operations use HTTP methods (GET, POST, PUT, DELETE). Simple and clear, REST is the de facto standard for public APIs.
Cache, auth, status codes — HTTP standards apply directly, so CDN acceleration and browser support are smooth. The weakness: clients fetch needed data from multiple endpoints, prone to N+1 problems (after a list query, fetching each related item one at a time, exploding requests) and over- / under-fetching.
| Typical pattern | Meaning |
|---|---|
GET /users | List |
GET /users/:id | Single fetch |
POST /users | Create |
PUT / PATCH /users/:id | Update |
DELETE /users/:id | Delete |
For public APIs, pick REST without hesitation — adoption and tooling overwhelm everything else.
REST design principles
When picking REST, follow these for a long-lived API. Not just style — guidelines aligned with HTTP’s design.
- Resource-oriented, use nouns (
/usersnot/getUsers). - HTTP methods express operations (GET/POST/PUT/DELETE).
- Use status codes correctly (200/201/400/401/404/500).
- URL hierarchy expresses relationships (
/users/123/orders). - Unify error-response format (RFC 7807 Problem Details is the default).
GraphQL
GraphQL, published by Facebook in 2015, is a query language where clients specify the shape of data they want. Instead of fixed REST endpoints, queries are sent to a single endpoint (typically /graphql) saying “this screen needs only these fields.”
Strong when Web, mobile, internal dashboards, and other clients want different shapes. Weaknesses: HTTP cache is hard, N+1 problems must be solved manually, server-side implementation difficulty exceeds REST.
| Strengths | Weaknesses |
|---|---|
| Fetch only the data needed | Cache strategy is complex |
| Auto-docs from typed schema | N+1 must be solved manually |
| Saves bandwidth on mobile | High learning cost |
| Good frontend developer experience | High server-implementation difficulty |
Worth considering for diverse-client APIs. Overspec for simple APIs.
gRPC
gRPC, developed by Google, is a binary-communication API framework using Protocol Buffers (Protobuf). Runs on HTTP/2 with bidirectional streaming, handling massive request volumes. Generates client and server code in many languages from .proto files — a major strength.
Schema-first with strict types makes it the first choice for microservice-to-microservice traffic. Direct browser use is hard (gRPC-Web required) and HTTP-tool debugging is awkward, so it’s a poor fit for public APIs.
| Strengths | Weaknesses |
|---|---|
| Overwhelming performance (binary) | Direct browser use is hard |
| Cross-language code generation | Hard to debug |
| Schema-first type safety | Hard to hit with HTTP tools (curl, etc.) |
| HTTP/2 streaming support | Mid-high learning cost |
First choice for microservice-to-microservice traffic. Poor fit for external publication.
WebSocket
WebSocket keeps a persistent connection between client and server with bidirectional traffic. Regular HTTP is “client asks, server answers” one-shot; WebSocket lets “the server actively push to the client” — decisively different.
This trait fits real-time use: chat, stock displays, online games, live streaming, notifications — “want to instantly notify clients of server-side state change” scenes default to WebSocket. After an HTTP handshake, the connection upgrades to a custom protocol.
| Strengths | Weaknesses |
|---|---|
| Low latency, bidirectional | Connection-keep resource use |
| Server can push | Load balancers and proxies need care |
| Browser-standard support | Reconnection logic is your code |
Specialized for real-time use cases REST can’t express; irreplaceable when the use matches.
Four-style comparison
The styles have clearly different sweet spots, so simple superiority comparison is meaningless. Typical-use comparison:
| Aspect | REST | GraphQL | gRPC | WebSocket |
|---|---|---|---|---|
| Public-API fit | ◎ | ◯ | × | △ |
| Browser support | ◎ | ◎ | △ | ◎ |
| Performance | ◯ | ◯ | ◎ | ◎ |
| Learning cost | Low | Mid | Mid | Low |
| Type safety | △ | ◎ | ◎ | × |
| Cache leverage | ◎ | △ | × | × |
The typical pattern: “public REST / internal gRPC / real-time WebSocket”.
Versioning strategy
Spec changes after publication are inevitable, so version management must be in from the start. Without versioning, every small change requires coordination with every consumer — “effectively, you can’t improve the API.”
| Method | Example | Trait |
|---|---|---|
| URL path | /api/v1/users | Simplest, widest adoption |
| Accept header | Accept: application/vnd.api.v1+json | Cleaner URL, higher learning cost |
| Query parameter | /api/users?version=1 | Easy, awkward at scale |
URL-path is simplest and most adopted. “This is the default” is fine.
API lifecycle ladder
Note: industry rates as of April 2026. Periodic refresh required.
Since APIs are “contracts on publish,” managing the phases pre-publication through retirement “by numbers” is the operations key.
| Phase | State | Support | Migration window |
|---|---|---|---|
| Beta / Preview | Experimental, spec changing | No SLA, breaking changes possible | — |
| GA (General Availability) | Stable, production OK | Backward compatibility maintained | — |
| Deprecated (discouraged) | New use discouraged | Continues working, warning headers | 6 months to 2 years minimum |
| Sunset | Retirement notice | Continues working, retirement date announced | 3 months minimum |
| EOL (end of life) | Stopped | Doesn’t work | — |
The industry standard: “Deprecation -> Sunset -> EOL window of at least 6 months.” Google Cloud / AWS / Stripe officially commit to 2+ years; failing this loses consumer trust.
Deprecation window: at least 6 months, ideally 2 years. Sudden retirement loses trust instantly.
Authentication methods
APIs always need authentication. Pick by use:
| Method | Use |
|---|---|
| Bearer Token (JWT — JSON Web Token, signed token) | Most common for SPA (Single Page Application) and mobile |
| OAuth 2.0 / OIDC | External-service integration, SSO |
| API Key | Server-to-server, B2B API |
| mTLS (mutual TLS) | Internal traffic with very high security needs |
External publication: OAuth 2.0. Internal: API Key or mTLS. Behind BFF: Cookie + session — these are practical defaults.
Rate-limit / error-design numeric gates
Note: industry rates as of April 2026. Periodic refresh required.
Leaving “things to decide” vague in API design causes production incidents. Set concrete numerical baselines first.
| Setting | Recommended | Reason |
|---|---|---|
| Rate limit (public API) | 60 req/min per user, 600 req/min per IP | Brute-force prevention + fairness |
| Rate limit (internal API) | 10,000+ req/sec allowed | Don’t restrict internal use |
| Timeout | 30s (GET) / 60s (POST) | HTTP convention upper bound |
| Payload upper bound | 1MB (REST) / 10MB (file upload) | DoS prevention |
| Versioning | URL-path (/v1) required | Most adopted, easy debugging |
| Error format | RFC 7807 (Problem Details) | Standardized error shape |
| Deprecation window | 6 months minimum, 2 years ideal | Industry convention |
Status codes: use “200 (success) / 201 (created) / 400 (client error) / 401 (unauthenticated) / 403 (unauthorized) / 404 (not found) / 409 (conflict) / 429 (rate exceeded) / 500 (server error)” correctly. “Returning 200 for all errors” is a textbook forbidden move — clients can’t handle errors.
Selection by case
Public Web APIs (for external developers)
REST. Beats others on adoption, tooling, learning cost. OpenAPI auto-generates docs.
Service with diverse clients (Web / mobile / IoT, etc.)
GraphQL. When clients want different data shapes, GraphQL is more efficient than maintaining many REST endpoints.
Microservice-to-microservice internal traffic
gRPC. Wins on performance, type safety, code generation. No browser direct access, so gRPC’s weakness doesn’t apply.
Real-time features (chat, notifications, games)
WebSocket. Irreplaceable for bidirectional traffic.
General web service + some real-time
REST + WebSocket combination. Many services use this pairing.
API-design traps
Common API-design failures, ordered by retroactive fix cost:
| Forbidden move | Why |
|---|---|
Verbs in URLs (/getUsers / /deleteUser) | Double-management with HTTP method. /users + GET/DELETE is correct |
All errors return 200 OK with {success: false} body | Client error handling breaks. Use HTTP standard status codes |
| Publish without versioning | Breaking changes impossible; API freezes. /v1 from day one |
| Auth bolted on later | All endpoints need modification. Design with auth assumed |
| No schema (OpenAPI / Protobuf / etc.) | Spec becomes oral tradition; client and implementation drift |
| N+1 queries via the API | DB load grows linearly. Use Include params or GraphQL |
| Pagination only via Offset | Performance breaks at scale. Provide cursor-based too |
| Breaking changes without notice | Consumer trust gone instantly. The X (Twitter) 2023 v1.1 monetization pattern |
| POST retries allowed without idempotency | Double payment / double inventory decrement. Use Idempotency-Key header |
| No rate limit | Bots / malicious use cause high bills and DoS |
| Adopting GraphQL on the premise “it’s newer, therefore better” | GraphQL is overspec for simple CRUD; cache strategy and N+1 handling actually increase dev effort |
| Unifying all internal traffic on gRPC | HTTP debug tools don’t apply, spiking incident-investigation difficulty; for small-scale integrations REST has lower operational cost |
Stripe’s API is industry-known as a “non-breaking API” model. Endpoints from the 2011 initial release are still running 10+ years later; “add features while preserving backward compatibility” is solved.
The iron rule of API design: “don’t break it, don’t kill it, don’t be vague.”
AI decision axes
| AI-era favorable | AI-era unfavorable |
|---|---|
| OpenAPI / GraphQL / gRPC (schema-first) | Specs in Excel / Word / oral |
| tRPC (TypeScript type sharing) | Untyped hand-written REST |
| Auto-generation from schema (types / clients / docs) | Hand-copying types into the client |
| Standard RESTful patterns | Custom naming, custom error formats |
- Split public vs internal first (external = REST, internal = gRPC candidate).
- Decide by consumer shape (Web / mobile / external developer / inter-service).
- Schema-first as a hard requirement (OpenAPI / Protobuf / GraphQL).
- Without a deviation reason, lean on REST (adoption, tooling, AI accuracy decisively favor it).
”An API that suddenly stopped” (industry case)
When X (formerly Twitter) effectively ended API v1.1 by monetizing in 2023, classic third-party clients like Tweetbot all stopped at once. From a consumer’s view, “API spec = perpetual contract” had been the assumption; one day it was suddenly ripped away.
Watching Tweetbot sink overnight on Twitter’s whim made many feel the contractual nature of APIs viscerally. The case is remembered as the most violent demonstration of “APIs are contracts.”
When API discussions say “naming can’t be changed later,” this is the reality on their mind.
API publication is contract execution; build retirement / change rules into the design from the start.
What you must decide — what’s your project’s answer?
Articulate your project’s answer in 1-2 sentences for each:
- API style (REST / GraphQL / gRPC / WebSocket / combination)
- Authentication (Bearer Token / OAuth / API Key / mTLS)
- Error response format (RFC 7807, etc.)
- Versioning strategy (URL path / Accept header)
- Rate limit (per user / per IP / req per minute)
- Documentation management (OpenAPI / GraphQL Schema / Protobuf)
- Public vs internal-only line
Summary
This article covered API design — four styles, versioning, auth, rate-limit numeric baselines.
External public: REST + OpenAPI. Internal: gRPC. Per-screen: GraphQL. Real-time: WebSocket. Schema-first, AI-friendly design is the modern favorite.
The next article covers frameworks (Spring / Next.js / FastAPI / Rails, etc.).
Back to series TOC -> ‘Architecture Crash Course for the Generative-AI Era’: How to Read This Book
I hope you’ll read the next article as well.
📚 Series: Architecture Crash Course for the Generative-AI Era (21/89)