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.
← Back to APIs & Networking/users/42, /orders/2026-04-29. Not verbs in URLs ever — /getUser?id=42 is RPC, not REST.GET (read), POST (create), PUT (replace), PATCH (partial update), DELETE (remove).200 OK, 201 Created, 204 No Content, 400 bad request, 404 not found, 409 conflict, 422 validation error, 429 rate-limited, 5xx server fault.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."
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.
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.
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.
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.
"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.
Once a public client is using /v1/users, you can't break that shape. Common strategies:
/v1/, /v2/. Simple, visible, what most public APIs use.Accept: application/vnd.example.v2+json. Cleaner URLs; harder to debug in a browser.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.
| Operation | Verb & Path | Status on Success |
|---|---|---|
| List users | GET /users | 200 |
| Get one user | GET /users/42 | 200 or 404 |
| Create user | POST /users | 201 + Location header |
| Replace user | PUT /users/42 | 200 or 204 |
| Patch user | PATCH /users/42 | 200 |
| Delete user | DELETE /users/42 | 204 |
| List a user's orders | GET /users/42/orders | 200 |
| Search | GET /users?email=x@y.com | 200 |
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-*).
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.