Rest-api
01 / 02

REST API Design

REST API Design

Resource Naming & HTTP Methods

# Use nouns (not verbs), plural, lowercase, hyphens
GET    /users              # list users
POST   /users              # create user
GET    /users/{id}         # get user
PUT    /users/{id}         # replace user (full update)
PATCH  /users/{id}         # partial update
DELETE /users/{id}         # delete user

# Nested resources
GET    /users/{id}/posts           # user's posts
POST   /users/{id}/posts           # create post for user
GET    /users/{id}/posts/{postId}  # specific post

# Actions that don't fit CRUD (use nouns when possible)
POST   /orders/{id}/cancel          # good
POST   /orders/{id}/cancellations   # RESTful noun variant
GET    /search?q=query&type=user    # search

# Don't use verbs in paths
# BAD:  POST /createUser, GET /getUser, POST /users/delete/{id}
# GOOD: POST /users,       GET /users/{id}, DELETE /users/{id}

HTTP Status Codes

# 2xx — Success
200 OK             — GET, PUT, PATCH responses
201 Created        — POST response; include Location: /users/{newId} header
204 No Content     — DELETE, or PATCH with no body response

# 3xx — Redirection
301 Moved Permanently   — permanent URL change
302 Found / 307 Temp    — temporary redirect
304 Not Modified        — ETag/If-None-Match cache hit

# 4xx — Client errors
400 Bad Request         — malformed request, validation failure
401 Unauthorized        — not authenticated (missing/invalid token)
403 Forbidden           — authenticated but not authorized
404 Not Found           — resource doesn't exist
405 Method Not Allowed  — wrong HTTP method for this endpoint
409 Conflict            — duplicate (unique constraint), optimistic lock conflict
410 Gone               — permanently deleted (vs 404 = never existed)
422 Unprocessable       — validation errors on valid JSON
429 Too Many Requests   — rate limited; include Retry-After header

# 5xx — Server errors
500 Internal Server Error  — unexpected error (never expose details)
502 Bad Gateway            — upstream service failed
503 Service Unavailable    — overloaded/down; include Retry-After header

Response Format

// Success — single resource
{
  "id": "usr_123",
  "email": "alice@example.com",
  "name": "Alice",
  "role": "user",
  "createdAt": "2024-01-15T10:30:00Z"
}

// Success — list with pagination
{
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 143,
    "totalPages": 8,
    "hasNextPage": true,
    "nextCursor": "eyJpZCI6MTIzfQ=="
  }
}

// Error response — consistent shape
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      { "field": "email", "message": "Invalid email format" },
      { "field": "password", "message": "Must be at least 8 characters" }
    ],
    "requestId": "req_abc123"
  }
}

Headers & Versioning

# Request headers
Content-Type: application/json
Accept: application/json
Authorization: Bearer <token>
X-Request-ID: client-generated-uuid
If-None-Match: "abc123"          # conditional GET (ETag)
If-Match: "abc123"               # optimistic concurrency check

# Response headers
Content-Type: application/json; charset=utf-8
X-Request-ID: req_abc123         # echo back for tracing
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1700000000
ETag: "abc123"                   # for caching
Location: /users/123             # after 201 Created
Retry-After: 60                  # after 429 or 503

# API Versioning strategies
# 1. URL path (most common, explicit)
GET /v1/users
GET /v2/users

# 2. Query parameter
GET /users?version=2

# 3. Header (cleanest, least visible)
Accept: application/vnd.api.v2+json
API-Version: 2

# Prefer URL versioning for public APIs — visible and cacheable

Filtering, Sorting & Pagination

# Filtering
GET /users?role=admin&isActive=true
GET /users?age_gte=18&age_lte=65
GET /posts?status=published&tag=javascript

# Sorting
GET /users?sort=name                 # ascending
GET /users?sort=-createdAt           # descending (minus prefix)
GET /users?sort=-createdAt,name      # multiple fields

# Field selection (sparse fieldsets)
GET /users?fields=id,name,email

# Pagination — offset
GET /users?page=2&limit=20

# Pagination — cursor (better for large datasets)
GET /users?cursor=eyJpZCI6MTIzfQ==&limit=20
# Response includes nextCursor for subsequent request

# Search
GET /users?q=alice
GET /posts?q=javascript&in=title,body

# Include relations
GET /posts?include=author,tags

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free