The API That Runs the Internet
Every time you open Instagram, pay with Stripe, or ask ChatGPT a question, a REST API is doing the work. The stock quotes on your phone, the weather widget on your laptop, the order status for the package on your doorstep — all delivered by REST. More than 80% of public web APIs today are REST, even in the age of GraphQL and gRPC.
Yet for something so universal, REST is widely misunderstood. Developers call anything that returns JSON over HTTP a "REST API," when most are really just HTTP APIs. Real REST, as defined by Roy Fielding in his 2000 PhD dissertation, has six specific constraints — and most "REST APIs" violate at least two of them.
This guide untangles REST from HTTP from JSON from RPC. You will learn what REST actually is, why it won, when it is the right choice, and how to design one that holds up in production. We will cover Fielding's six constraints, the HTTP verb to CRUD mapping, resource modeling, idempotency, auth, rate limiting, versioning, and pagination — with real examples from Stripe, GitHub, and Twitter.
What Is a REST API?
REST stands for Representational State Transfer. It is an architectural style for distributed systems, introduced by Roy Fielding — one of the authors of the HTTP/1.1 specification — in chapter 5 of his 2000 doctoral dissertation at UC Irvine.
A REST API is an API that follows the REST architectural style. In practice, that means the API:
- exposes resources (users, orders, products) at URLs - uses standard HTTP verbs (GET, POST, PUT, PATCH, DELETE) to act on those resources - represents resources as data (usually JSON, sometimes XML) - is stateless — each request carries everything needed to process it - uses HTTP status codes to signal outcomes
A minimal REST interaction looks like this:
GET /users/42 HTTP/1.1 Host: api.example.com Accept: application/json
HTTP/1.1 200 OK Content-Type: application/json
{"id":42,"email":"jane@example.com","plan":"pro"}
The URL identifies a resource. The verb says what to do. The body is a representation. The status code reports the outcome. That is REST in one breath.
You can try this live against any public REST API at /api-client — point it at https://api.github.com/users/octocat and see the whole thing.
Fielding's Six REST Constraints
Fielding did not invent REST to sell books. He was describing the architectural principles behind the web's scalability. Violating these constraints is what turns a REST API into "REST in name only."
1. Client-Server. Separation of concerns. The UI and data layer evolve independently. Your iOS app and your web app both talk to the same API.
2. Stateless. Every request must contain all information needed to process it. The server stores no client context between requests. This is why auth tokens travel on every request — servers do not remember you. Statelessness enables horizontal scaling: any server can handle any request.
3. Cacheable. Responses must declare whether they are cacheable (via Cache-Control, ETag, Last-Modified). This is how CDNs can offload 95% of read traffic for sites like Wikipedia.
4. Uniform Interface. The same four sub-constraints apply across all resources: identification (URLs), manipulation through representations, self-descriptive messages (content types, status codes), and HATEOAS (hypermedia). This is the constraint most "REST" APIs skip.
5. Layered System. The client does not know whether it is talking to the origin server or a proxy, CDN, or API gateway. This enables Cloudflare, AWS API Gateway, and every reverse proxy in your stack.
6. Code on Demand (optional). The server can send executable code to the client — JavaScript in browsers is the canonical example.
Most APIs nail the first five constraints for reads and skip HATEOAS. That is why they are sometimes called "RESTish" rather than RESTful.
HTTP Verbs and CRUD Mapping
REST uses HTTP verbs to express intent. The standard mapping to CRUD operations:
Operation — HTTP verb • Example Create — POST • POST /users Read (list) — GET • GET /users Read (one) — GET • GET /users/42 Update (full) — PUT • PUT /users/42 Update (partial) — PATCH • PATCH /users/42 Delete — DELETE • DELETE /users/42
Key properties to remember:
- GET is safe (no side effects) and idempotent (repeatable). - POST is neither safe nor idempotent — calling it twice creates two resources. - PUT is idempotent — replacing a resource twice yields the same state. - PATCH is idempotent when implemented with RFC 7396 merge-patch; not guaranteed otherwise. - DELETE is idempotent — deleting a deleted resource is a no-op (204 or 404).
Idempotency matters for retries. If a client times out on a PUT, it can safely retry. It cannot safely retry a POST without an idempotency key — which is why Stripe requires an Idempotency-Key header on every POST. For a full breakdown see /blog/http-methods-explained.
Resource-Oriented URLs
REST thinks in nouns, not verbs. The URL identifies a resource; the verb acts on it.
Good:
GET /articles GET /articles/42 POST /articles DELETE /articles/42/comments/7
Bad (RPC style):
GET /getAllArticles POST /createArticle POST /deleteArticle?id=42
The "users vs user" debate is settled: use plural nouns consistently. /users, /orders, /products. The singular form is ambiguous — does /user mean the current user or any user? Plural is unambiguous.
Nest resources only when the child cannot exist without the parent. /users/42/orders is fine because an order belongs to a user. Do not nest more than two levels deep — /users/42/orders/7/items/3/tags/5 is unreadable. Flatten: /items/3/tags or /order-items/3.
Use query parameters for filtering, sorting, and pagination:
GET /articles?author=42&status=published&sort=-created_at&page=2&per_page=25
GitHub, Stripe, and Shopify all follow these conventions.
Real-World REST API Examples
Let us look at how the biggest APIs in the world do it.
Stripe — the canonical REST API. Every resource is plural and lowercase: /v1/customers, /v1/charges, /v1/subscriptions. POSTs require Idempotency-Key. Errors return structured JSON with type, code, and message. Versioning is via Stripe-Version header, allowing customers to pin a date-based version like 2024-10-28.
GitHub — also textbook REST. /users/{username}, /repos/{owner}/{repo}/issues, /repos/{owner}/{repo}/pulls/{number}/reviews. Rate limits exposed via X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset headers. Conditional requests with ETag return 304 Not Modified and do not count against rate limits — a huge optimization.
Twitter (X) API v2 — RESTful with a twist: cursor-based pagination instead of offset. GET /2/tweets/search/recent?query=nodejs&next_token=... scales better than offset pagination for large datasets.
Shopify Admin API — REST and GraphQL side by side, which shows the two styles can coexist. REST for CRUD, GraphQL for complex relational queries.
Common patterns across all four: plural resources, HTTP verbs, JSON bodies, structured errors, rate-limit headers, versioning, and Bearer-token auth. Modeling your API on these is rarely wrong.
Authentication, Rate Limiting, and Versioning
Authentication. Three schemes dominate:
- API keys (sent as Authorization: Bearer sk_live_... or a custom X-API-Key header). Simple, good for server-to-server. - OAuth 2.0 — the standard for user-authorized third-party access. Access tokens are typically JWTs. See /blog/jwt-tokens-explained. - Signed requests (AWS SigV4, HMAC) — for high-security use cases.
Always send credentials over HTTPS. Never in URLs — they leak into logs.
Rate limiting. Protects your API from abuse and yourself from overload. Return 429 Too Many Requests with Retry-After. Expose quota with RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset headers (the IETF draft standard). Typical tiers: 100 req/min for free, 1000 for pro, higher for enterprise.
Versioning. Two common approaches:
- URL versioning: /v1/users, /v2/users. Easy to see, easy to route, easy to cache. Used by Twitter, GitHub. - Header versioning: Stripe-Version: 2024-10-28 or Accept: application/vnd.example.v2+json. Cleaner URLs, allows more granular versions. Used by Stripe, GitHub v3.
Pick one and be consistent. Avoid breaking changes within a version; when you must break, bump the version and keep the old one running for at least 12 months. For more on securing versioned APIs see /blog/api-security-best-practices.
Pagination, Filtering, and HATEOAS
Never return unbounded lists. Three pagination patterns:
Offset pagination: ?page=3&per_page=25. Simple, but slow on large tables (OFFSET scans) and breaks when rows are inserted.
Cursor pagination: ?cursor=eyJpZCI6MTAwfQ&limit=25. Opaque cursor encodes the last seen row. Scales to billions of rows. Used by Twitter, Slack, Stripe (starting_after).
Keyset pagination: ?after_id=100&limit=25. Like cursor but human-readable.
Return a Link header for navigation (RFC 8288):
Link: <https://api.example.com/users?cursor=abc>; rel="next", <https://api.example.com/users?cursor=xyz>; rel="prev"
HATEOAS (Hypermedia As The Engine Of Application State) is the uniform-interface sub-constraint most APIs skip. It means the response contains links to available actions:
{"id":42,"status":"pending", "_links":{ "self":{"href":"/orders/42"}, "cancel":{"href":"/orders/42/cancel","method":"POST"}}}
PayPal and GitHub v3 are notable HATEOAS-ish examples. In practice, most successful APIs (Stripe, Twilio) skip HATEOAS and document URLs directly — and Fielding has publicly lamented this.
REST vs SOAP vs GraphQL vs gRPC
REST is not the only game in town.
Feature — REST • SOAP • GraphQL • gRPC Transport — HTTP • HTTP/SMTP • HTTP • HTTP/2 Payload — JSON • XML • JSON • Protobuf Schema — Optional (OpenAPI) • WSDL (required) • SDL (required) • Protobuf (required) Caching — HTTP native • Complex • Manual • Manual Browser support — Native • Poor • Native • Needs gRPC-Web Strengths — Simple, cached, universal • Enterprise, transactions • Flexible queries, one round-trip • Fast, typed, streaming Weaknesses — Over/under-fetching • Verbose, legacy • Caching, complexity • Not browser-native
When to choose each:
- REST — public APIs, CRUD apps, anything consumed by browsers or third parties. Default choice. - SOAP — legacy enterprise (banking, healthcare integrations). Avoid for greenfield. - GraphQL — mobile clients with varied data needs, complex relational graphs (Facebook, Shopify). - gRPC — high-performance internal microservices, streaming, polyglot backends (Google, Netflix internal).
In 2026, most architectures use two or three: REST at the edge, gRPC between services, GraphQL for specific clients.
Common Mistakes in REST API Design
Verbs in URLs. /getUsers, /createOrder. This is RPC, not REST. Use nouns and HTTP verbs.
Returning 200 for errors. {"status":"error"} with a 200 breaks every HTTP-aware tool. Use proper status codes — see /blog/http-status-codes-guide.
Inconsistent naming. /users, /Order, /product_items. Pick a case (snake_case or camelCase) and stick to it. JSON typically uses camelCase; URL paths use kebab-case.
No pagination. /users returns 10 million rows and takes down your database. Paginate from day one.
Breaking changes without versioning. Silently renaming a field breaks every client. Bump the version or add a new field.
Ignoring idempotency on POST. Retries create duplicates. Accept an Idempotency-Key header.
Leaking internal errors. 500 Internal Server Error with a stack trace in the body is a security hole. Log the details; return a generic message and a correlation ID.
Frequently Asked Questions
Is REST the same as HTTP? No. HTTP is a protocol; REST is an architectural style that happens to map cleanly onto HTTP. You could, in theory, build a REST API over another protocol, though no one does. Most "REST APIs" are really HTTP+JSON APIs with resource-oriented URLs and verb usage.
Is REST dying because of GraphQL? No. Public API catalogs (ProgrammableWeb, RapidAPI) still show REST as 80%+ of APIs in 2026. GraphQL is winning in specific niches — mobile apps, complex relational data — but REST remains the default for public APIs because of simplicity, HTTP caching, and universal tooling.
What is the difference between REST and RESTful? Pedantically: REST is the style; RESTful is an API that follows the style. Practically, people use them interchangeably. "RESTish" is sometimes used for APIs that follow most but not all constraints — particularly those that skip HATEOAS.
Do REST APIs have to use JSON? No. REST is format-agnostic. XML, YAML, Protobuf, even HTML are valid representations. JSON wins because it is compact, native to browsers, and human-readable. Content negotiation via the Accept header lets one API serve multiple formats.
Can REST APIs push data to clients? Not natively — REST is request/response. For push, layer WebSockets, Server-Sent Events, or webhooks on top. Stripe and GitHub both combine REST for queries with webhooks for events.
How do I test a REST API? Use a tool like the StringTools API Client at /api-client, Postman, curl, or HTTPie. Automated testing uses libraries like supertest (Node), requests (Python), or REST Assured (Java). Contract testing with OpenAPI schemas and tools like Dredd catches breaking changes.
What is OpenAPI and how does it relate to REST? OpenAPI (formerly Swagger) is a specification for describing REST APIs in YAML or JSON. It enables auto-generated docs, client SDKs, and server stubs. It is not REST itself but the de facto standard for documenting REST APIs.
Conclusion
REST won because it is simple, cacheable, and universal. Nail the basics — resource URLs, HTTP verbs, status codes, stateless requests, structured errors — and your API will be understood by every developer and every tool on the planet.
Building a REST API? Test it as you go. The StringTools API Client at /api-client is a free, browser-based tool for sending any method to any endpoint, inspecting headers and status codes, and saving request collections. Pair it with /blog/api-security-best-practices and /blog/jwt-tokens-explained as you harden your API for production.
REST is not glamorous. It is just consistently the right call.
Related Tools and Reading
Try the StringTools API Client at /api-client to send real requests to any REST API.
Related reading: /blog/http-methods-explained for a verb-by-verb breakdown, /blog/http-status-codes-guide for what to return, /blog/api-security-best-practices for hardening, /blog/jwt-tokens-explained for token-based auth, and /blog/cors-explained for cross-origin access.