API Styles Deep Dive · 1 of 7

REST — Resources, Verbs, and the Web's Native API Style

REST models the world as resources at URLs and acts on them with HTTP verbs. It's not a protocol — it's an architectural style — but it has become the lingua franca of public web APIs because it cooperates with everything the web already does: caching, proxying, authentication, debugging.

HTTPJSONStatelessCacheablePublic APIs
← Back to APIs & Networking
Quick Facts

What REST Is

Basic Concepts

  • Origin: Roy Fielding's 2000 PhD dissertation. "Representational State Transfer."
  • Resources: nouns at URLs. /users/42, /orders/2026-04-29. Not verbs in URLs ever — /getUser?id=42 is RPC, not REST.
  • Verbs: GET (read), POST (create), PUT (replace), PATCH (partial update), DELETE (remove).
  • Stateless: the server doesn't remember the client between calls. Each request carries everything it needs.
  • Representations: JSON is the default; XML, CSV, even HTML are valid REST responses.
  • Status codes do real work: 200 OK, 201 Created, 204 No Content, 400 bad request, 404 not found, 409 conflict, 422 validation error, 429 rate-limited, 5xx server fault.
Why It Wins

What You Buy

Ubiquitous Tooling

Every language has an HTTP client. Every browser dev-tools panel speaks HTTP. curl, Postman, Insomnia, browser extensions — debugging a REST call requires nothing exotic. The barrier to integration for any third-party developer is "you already have what you need."

CDN-Friendly Caching

GET is cacheable by default. CloudFront, Fastly, browsers, and corporate proxies all cache REST responses based on Cache-Control, ETag, Last-Modified. A well-designed REST API serves most of its read traffic from cache without the origin server seeing it.

Stateless Scales Horizontally

No session affinity. Any request can hit any server. Add ten replicas behind a load balancer and you've ten-x'd your capacity. This is why REST is the default behind every kubectl scale.

Self-Describing

The verb describes the action; the URL describes the resource; the status code describes the outcome; the headers describe the metadata. A response is readable by a human and a machine without an SDK.

Where It Hurts

The Real Pain Points

Over-fetching and Under-fetching

Over-fetch: GET /users/42 returns the whole user when you wanted only the name. Wasted bandwidth on every request.

Under-fetch: rendering one screen needs /users/42, /users/42/orders, /orders/100/items — three round-trips, each adding latency. The N+1 problem of HTTP APIs.

This is GraphQL's entire pitch. REST mitigates with sparse fieldsets (?fields=name,email), expansion (?include=orders), and BFF aggregator endpoints — none as elegant.

No Schema by Default

"What does this endpoint return?" Read the docs, hope they're current. OpenAPI / Swagger fixes this — bolt on a schema, generate clients and docs — but it's an addition, not native to REST. Compare with gRPC where the schema is the API.

Versioning Is Forever

Once a public client is using /v1/users, you can't break that shape. Common strategies:

  • URL versioning: /v1/, /v2/. Simple, visible, what most public APIs use.
  • Header versioning: Accept: application/vnd.example.v2+json. Cleaner URLs; harder to debug in a browser.
  • Additive evolution: never break — only add optional fields. Most APIs do this in practice within a major version.
HATEOAS — The Purist Version Nobody Ships

The original REST dissertation requires "Hypermedia as the Engine of Application State" — responses include links to next actions. In practice, almost no API does it; clients hard-code URLs. The pragmatic REST you'll meet in the wild is "RPC-flavored REST" — and that's fine.

Conventions

What "Good REST" Looks Like

OperationVerb & PathStatus on Success
List usersGET /users200
Get one userGET /users/42200 or 404
Create userPOST /users201 + Location header
Replace userPUT /users/42200 or 204
Patch userPATCH /users/42200
Delete userDELETE /users/42204
List a user's ordersGET /users/42/orders200
SearchGET /users?email=x@y.com200

Production extras: idempotency keys on POST, cursor pagination (not page numbers — they break under writes), ETag on GET, problem-detail JSON (RFC 9457) for errors, rate-limit headers (X-RateLimit-*).

Decision

When to Pick REST

  • Public APIs, third-party integrations, partner ecosystems — REST's tooling and discoverability win every time.
  • Browser-facing APIs where you want CDN caching to do real work.
  • CRUD-shaped surfaces where the resource model fits naturally.
  • When you need the API to be debuggable from a terminal or a browser dev-tools panel.

Reach for GraphQL instead when one screen needs nested data from many backends. Reach for gRPC for service-to-service inside your platform where binary speed and schema-first matter. Reach for WebSockets or SSE when the conversation is long-lived rather than request/response.

Continue

Other API Styles