foundations · level 4

REST APIs

Resource modelling, URLs, verbs, idempotency, versioning.

175 XP

REST APIs

REST (Representational State Transfer) is a set of constraints for designing HTTP APIs. It is not a standard or a protocol — it is a style. An API is "RESTful" when it treats resources as nouns, HTTP methods as verbs, and URLs as stable addresses for those resources.

Analogy

A REST API is like a well-organised filing cabinet in a busy office. Every folder (resource) has a permanent label and a fixed location — the "Customers" drawer, folder 42, subfolder "Orders" — so anyone who knows the filing system can find the same paper again tomorrow. You do not invent new verbs for every task: you slide a paper in (POST), pull one out to read (GET), replace a whole sheet (PUT), cross out one line with a pen (PATCH), or shred the folder (DELETE). The cabinet itself never renames its drawers to match what you plan to do — it just holds nouns, and staff do the verbs.

Resources and URLs

A resource is any thing your API manages: a user, an order, a file. Each resource has a URL. URLs should be stable, lowercase, and noun-based — they identify things, not actions.

/users           ← the collection of all users
/users/42        ← one specific user
/users/42/posts  ← posts belonging to user 42
/posts           ← the collection of all posts
/posts/7         ← one specific post

Avoid verbs in URLs. /users/42/deactivate is not RESTful. Instead: PATCH /users/42 with { "active": false } in the body.

Verbs on resources

Map HTTP methods to CRUD operations:

Method URL What it does
GET /users List all users
POST /users Create a new user
GET /users/42 Fetch user 42
PUT /users/42 Replace user 42 entirely
PATCH /users/42 Partially update user 42
DELETE /users/42 Delete user 42

Idempotent vs safe

Safe Idempotent
GET Yes Yes
HEAD Yes Yes
POST No No
PUT No Yes
PATCH No No*
DELETE No Yes

*PATCH can be made idempotent if you design the body carefully (e.g., { "set": { "name": "Sam" } } rather than { "increment": { "loginCount": 1 } }).

Response shape conventions

Collections return arrays:

{
  "data": [
    { "id": 1, "name": "Alice" },
    { "id": 2, "name": "Bob" }
  ],
  "meta": { "total": 2, "page": 1 }
}

Single items return objects:

{
  "id": 42,
  "name": "Sam",
  "email": "sam@example.com",
  "createdAt": "2025-01-15T10:30:00Z"
}

Errors should be consistent:

{
  "error": "not_found",
  "message": "User 42 does not exist",
  "status": 404
}

Versioning

APIs break clients when they change. Version your API from day one.

URL versioning (most common, most explicit):

/v1/users
/v2/users

Header versioning:

Accept: application/vnd.example.v2+json

URL versioning is simpler to route, cache, and debug. Run both versions in parallel while clients migrate. When v1 traffic hits zero, decommission it.

Pagination

Never return unbounded collections. Limit with:

GET /users?page=1&per_page=25
GET /users?cursor=eyJpZCI6MjV9&limit=25

Include navigation links or cursor in the response so clients don't need to guess:

{
  "data": [...],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 312,
    "next": "/v1/users?page=2&per_page=25"
  }
}

What REST is not

REST does not require JSON. It works with any content type. REST does not require HTTPS, though you should always use it. REST is not RPC — do not model procedures (/sendEmail) as REST endpoints. REST also does not prescribe authentication; that is a separate concern.