Backend Transport

REST API: Architecture and Best Practices

Roy Fielding published his dissertation in 2000 describing REST as an architectural style for scalable distributed systems. Most APIs calling themselves REST violate at least three of his six constraints - and still work perfectly well. The question is which violations are critical and which are reasonable trade-offs.

  • **Stripe API** - the gold standard of REST design: resource naming, Idempotency-Key for payments, URI versioning (/v1/), detailed status codes
  • **GitHub REST API** - HATEOAS-like `_links` in responses, pagination via Link header, versioning via Accept header
  • **Twitter/X API v2** - migration from RPC-style v1 (`/statuses/show.json`) to resource-based v2 (`/tweets/{id}`) as a breaking migration example
  • **PayPal API** - one of the few public APIs with genuine HATEOAS, `_links` govern the payment flow

The 6 REST Constraints

In 2000, Roy Fielding published his doctoral dissertation describing REST as an architectural style for distributed hypermedia systems. Most APIs calling themselves REST violate at least three of his six constraints.

REST stands for **Representational State Transfer**. It is not a protocol or standard - a set of architectural constraints. HTTP is the de facto implementation, but REST is theoretically applicable to any protocol.

  • **Uniform Interface** - a consistent way to interact with resources: resources identified by URI, manipulation through representations, self-descriptive messages
  • **Stateless** - each request contains all information needed to process it; the server stores no client state between requests
  • **Cacheable** - responses must explicitly declare whether they are cacheable (`Cache-Control`, `ETag`)
  • **Client-Server** - separation of concerns: UI and data storage are decoupled and can evolve independently
  • **Layered System** - the client has no way to tell whether it is connected directly to the end server or an intermediary
  • **Code on Demand** (optional) - servers can send executable code to clients (JavaScript)

**Why Stateless is critical for scaling:** if a server stores session state in memory, each subsequent request from the same client must reach the same instance. With stateless design any instance handles any request - horizontal scaling without sticky sessions.

**REST != HTTP.** REST is an architectural style. HTTP is a protocol. REST describes how to build systems; HTTP describes how to transfer data. REST constraints can be violated over HTTP (stateful APIs) or followed over other protocols.

A client receives a JWT token on login and sends it in every request. Which REST constraint does this implement?

Resource Design and HTTP Methods

The most common mistake is naming endpoints as actions (`/getUser`, `/createOrder`, `/deleteItem`). In REST, a URI identifies a **resource**, not an action. The action is conveyed by the HTTP method.

MethodActionIdempotentSafeExample
GETRetrieve resourceYesYesGET /users/123
POSTCreate resourceNoNoPOST /orders
PUTReplace resource entirelyYesNoPUT /users/123
PATCHPartial updateNo*NoPATCH /orders/456
DELETEDelete resourceYesNoDELETE /items/789

HTTP status codes are part of the REST language. Clients should understand the outcome of an operation without parsing the response body.

CodeMeaningWhen to use
200 OKSuccess with bodyGET, PUT, PATCH - resource is returned
201 CreatedCreatedPOST - new resource created, include Location header
204 No ContentSuccess without bodyDELETE, PUT when body is not needed
400 Bad RequestClient errorInvalid JSON, missing required fields
401 UnauthorizedNo authenticationToken absent or expired
403 ForbiddenNo permissionToken valid, but no access to resource
404 Not FoundResource not foundID does not exist
409 ConflictState conflictDuplicate email, uniqueness violation
422 UnprocessableSemantic errorJSON valid but data is incorrect
500 Internal ErrorServer errorUnexpected exception

**Anti-pattern:** returning `200 OK` with `{"success": false, "error": "Not found"}`. This forces clients to parse the body to determine success - it defeats the purpose of HTTP status codes.

Which HTTP method is correct for 'add item to cart' when the cart already exists?

Idempotency and Safety

Networks are unreliable: a request may be sent but the response may be lost. The client does not know whether the operation was completed. The natural solution is to retry. But what if the server executes it twice?

Two independent properties of HTTP operations: **idempotency** (repeated calls produce the same result) and **safety** (no side effects).

MethodIdempotentSafeExplanation
GETYesYesRead-only - repeated GET returns the same data
HEADYesYesLike GET, but no body
OPTIONSYesYesReturns supported methods
PUTYesNoPUT /users/1 with the same data - result is the same
DELETEYesNoDELETE twice: first deletes, second returns 404, state is the same
POSTNoNoPOST /orders creates a new order each time
PATCHNo*NoPATCH SET balance=100 is idempotent; PATCH balance+=10 is not

**Stripe, Braintree, Adyen** - all major payment systems implement Idempotency-Key. The client generates a UUID before the request and passes it in a header. Servers store responses for 24-72 hours. This is the standard pattern for financial operations.

DELETE /users/42 is called twice. The first call deleted the user; the second returned 404. Is DELETE idempotent?

API Versioning

APIs change - fields are added, structures evolve, endpoints are removed. When clients (mobile apps, partners) cannot update instantly, a strategy for version coexistence is needed.

The key distinction: **breaking changes** require a new version; **non-breaking changes** do not.

Breaking changeNon-breaking change
Removing a field from the responseAdding a new optional field
Renaming a fieldAdding a new endpoint
Changing a field type (string to number)Adding new HTTP methods
Changing the semantics of an existing fieldExtending an enum with new values (carefully)
Changing the URL structureAdding optional query parameters

**Sunset strategy:** when releasing v2, do not delete v1 immediately. Add a `Sunset: Sat, 01 Jan 2026 00:00:00 GMT` header to v1 responses - clients can log it and plan migration accordingly.

In v1, the field `user.name` returns a string. The new version needs to split it into `firstName` and `lastName`. Is this a breaking change?

HATEOAS: Hypermedia Links in Responses

HATEOAS - Hypermedia As The Engine Of Application State - is the last and least commonly implemented REST constraint. The idea: a server response contains both data and links to the available next actions.

In practice, the vast majority of 'REST APIs' are RPC-over-HTTP: verbs in URLs or hardcoded routes with no hypermedia links. Fielding publicly criticized such APIs, stating they are 'not REST'.

**When HATEOAS is genuinely useful:** long-lived public APIs (PayPal API uses HATEOAS) where clients are third-party developers who should not hardcode URLs. For internal microservice APIs HATEOAS is typically overkill.

Any JSON API over HTTP is a REST API

REST is a set of 6 architectural constraints. Most HTTP APIs violate at least Stateless or Uniform Interface

The term REST became a marketing synonym for 'not SOAP'. Fielding wrote in 2008: 'REST APIs must be hypertext-driven', criticizing the misuse of the term

An API returns an order with `_links.pay` and `_links.cancel`. When status is 'shipped' these links are absent. What does this provide?

REST API: Key Ideas

  • REST is Fielding's 6 architectural constraints from 2000; Stateless is critical for horizontal scaling
  • URI identifies a resource (noun), HTTP method conveys the action; status codes carry semantics without body parsing
  • Idempotency (GET/PUT/DELETE) enables safe retries; Idempotency-Key solves the POST duplication problem
  • HATEOAS is rarely implemented but conceptually important: the server controls valid state transitions

Related Topics

REST is a synchronous interaction protocol that exists alongside other API design approaches:

  • GraphQL — REST alternative: one endpoint, client defines response shape
  • gRPC — Binary protocol over HTTP/2, alternative for microservices
  • HTTP Fundamentals — Transport layer of REST: methods, headers, status codes

Вопросы для размышления

  • How does idempotency differ from safety in HTTP methods, and why is DELETE idempotent despite modifying state?
  • Under what conditions does HATEOAS add genuine value, and when does it become unnecessary complexity?
  • How does the Stateless REST constraint influence the choice of authentication mechanism (sessions vs JWT)?

Связанные уроки

  • net-22-http-headers
REST API: Architecture and Best Practices

0

1

Sign In