REST API Patterns

RESTful API design patterns, status codes, and request construction.

HTTP Methods

GET — retrieve resources
# List collection with filters
curl -s https://api.example.com/v1/devices?status=active&limit=50 | jq .

# Read single resource by ID
curl -s https://api.example.com/v1/devices/42 | jq .
POST — create a new resource
curl -s -X POST https://api.example.com/v1/devices \
  -H "Content-Type: application/json" \
  -d '{"name": "sw-core-01", "type": "switch", "vlan": 10}' | jq .
# Returns 201 Created with Location header
PUT — full replacement (idempotent, client sends ALL fields)
curl -s -X PUT https://api.example.com/v1/devices/42 \
  -H "Content-Type: application/json" \
  -d '{"name": "sw-core-01", "type": "switch", "vlan": 20, "status": "active"}' | jq .
PATCH — partial update (only changed fields)
curl -s -X PATCH https://api.example.com/v1/devices/42 \
  -H "Content-Type: application/json" \
  -d '{"vlan": 30}' | jq .
DELETE — remove resource (idempotent, returns 204)
curl -s -X DELETE https://api.example.com/v1/devices/42
# 204 No Content on success

Status Codes

Success (2xx)

Code Meaning

200 OK

GET, PUT, PATCH success with response body

201 Created

POST success, new resource created, check Location header

204 No Content

DELETE success, no response body

Redirection (3xx)

Code Meaning

301 Moved Permanently

Resource relocated, update bookmarks

304 Not Modified

Client cache is valid, no body returned

Client Error (4xx)

Code Meaning

400 Bad Request

Malformed syntax — missing field, wrong type

401 Unauthorized

Missing or invalid credentials (really "unauthenticated")

403 Forbidden

Valid credentials but insufficient permissions

404 Not Found

Resource does not exist

409 Conflict

State conflict — duplicate creation, version mismatch

422 Unprocessable

Valid syntax but semantic error — validation failure

429 Too Many Requests

Rate limit exceeded, check Retry-After header

Server Error (5xx)

Code Meaning

500 Internal Server Error

Unhandled exception on server

502 Bad Gateway

Upstream service failed

503 Service Unavailable

Overloaded or maintenance, check Retry-After

Headers

Essential request headers
curl -s https://api.example.com/v1/devices \
  -H "Content-Type: application/json" \     # body format
  -H "Accept: application/json" \           # desired response format
  -H "Authorization: Bearer $TOKEN" \       # authentication
  -H "X-Request-ID: $(uuidgen)"            # distributed tracing
Conditional requests — ETag-based caching
# First request -- server returns ETag
etag=$(curl -sI https://api.example.com/v1/devices/42 | grep -i etag | awk '{print $2}' | tr -d '\r')

# Subsequent request -- 304 if unchanged, saves bandwidth
curl -s -H "If-None-Match: $etag" https://api.example.com/v1/devices/42
Optimistic concurrency — prevent lost updates
# Include ETag from GET in the PUT/PATCH
curl -s -X PUT https://api.example.com/v1/devices/42 \
  -H "If-Match: \"$etag\"" \
  -H "Content-Type: application/json" \
  -d '{"name": "updated-name", "vlan": 20}'
# 412 Precondition Failed if resource changed since read
Idempotent POST — client-generated key prevents double-create
curl -s -X POST https://api.example.com/v1/orders \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"item": "firewall-license", "quantity": 1}'

Query Parameters

Filtering, sorting, field selection, expansion
# Filter
curl -s "https://api.example.com/v1/devices?type=switch&status=active"

# Sort (- prefix = descending)
curl -s "https://api.example.com/v1/devices?sort=-created_at,name"

# Sparse fieldsets -- only requested fields
curl -s "https://api.example.com/v1/devices?fields=id,name,status"

# Resource expansion -- embed related objects, avoid N+1
curl -s "https://api.example.com/v1/devices?include=interfaces,vlans"

HATEOAS

Hypermedia links — response includes navigable API structure
{
  "id": 42,
  "name": "sw-core-01",
  "_links": {
    "self": "/v1/devices/42",
    "interfaces": "/v1/devices/42/interfaces",
    "vlans": "/v1/devices/42/vlans",
    "collection": "/v1/devices"
  }
}