REST API Design

REST is a set of conventions for building HTTP APIs that are predictable, cacheable, and easy to evolve. Done well, a REST API feels like a well-organized filing cabinet. Done badly, it is a maze.

What REST actually is (and is not)

REST stands for Representational State Transfer. Roy Fielding coined it in 2000. It is not a protocol, it is a set of architectural constraints that, when followed, give you APIs that are easy to consume, cache, and evolve. Most APIs that call themselves REST follow some of the rules. The fully strict version (HATEOAS, hypermedia) is rare in practice. What everyone means by REST today is "JSON over HTTP, organized around resources, using HTTP methods sensibly".

The core ideas

  1. Resources. Everything is a resource: a user, an order, a comment. Each has a URL.
  2. Standard methods. Use GET to read, POST to create, PUT/PATCH to update, DELETE to delete. Do not invent verbs in the URL.
  3. Stateless. Each request carries everything needed. Servers do not remember sessions between calls; they look them up from a token.
  4. JSON representations. Resources are returned as JSON (mostly).
  5. Cacheable. Responses signal whether and how long they can be cached.

Designing the URL structure

URLs name resources, not actions. Use nouns, plural, in lower case, with hyphens.

Good:

GET    /users           list users
GET    /users/42        get user 42
POST   /users           create user
PATCH  /users/42        update user 42
DELETE /users/42        delete user 42

GET    /users/42/orders         list orders for user 42
GET    /orders/9911/items       items in order 9911

Avoid:

POST /getUser
GET  /createOrder?userId=42
POST /users/42/delete

Verbs in URLs make APIs feel like RPC and are harder to evolve. Stick to nouns and let the HTTP method express the action.

RESOURCE-ORIENTED URLS GET /products/123/reviews → list of reviews for product 123 POST /products/123/reviews → create a new review PATCH /reviews/9911 → partially update review 9911
Same noun (review), different methods. The URL identifies the resource, the method describes the action.

Versioning

APIs change. Clients out in the wild do not. You need a way to evolve without breaking them. Three common approaches:

Pick one and stick to it. URL versioning is fine for most teams.

Pagination

Never return unbounded lists. They will grow until they break. Three pagination styles:

Filtering, sorting, and sparse fields

Common conventions:

These are not REST commandments, just common patterns. Whatever you choose, document it and stay consistent across endpoints.

Error responses that help

A 400 with no body is hostile. Always return a structured error.

{
  "error": {
    "code": "validation_failed",
    "message": "Email is invalid",
    "field": "email",
    "trace_id": "abc-123"
  }
}

Include a code (machine-readable), a message (human-readable), and a trace ID so support can find the request in logs.

The smell test for an API Read the URL alone, no docs. Can a stranger guess what it does? "DELETE /accounts/42/sessions/current" is obvious. "POST /api/handle" is not. Good APIs feel like they were designed to be read.

HATEOAS, briefly

The strict REST original includes HATEOAS: each response embeds links to related resources, so the client navigates by following links rather than building URLs. Almost no production API does this fully. The exceptions (GitHub, PayPal partly) usually have very long-lived clients. For most teams, plain JSON with documented URLs is enough. Do not let HATEOAS guilt push you into over-engineering.

REST is mostly about discipline. Pick conventions, document them, apply them everywhere. The first ten endpoints set the precedent for the next thousand. Get them right.