All skills
Skillintermediate

REST Design Patterns

REST APIs are built around resources, not actions. Resources are the nouns of your API.

Claude Code Knowledge Pack7/10/2026

Overview

REST Design Patterns

Resource-Oriented Architecture

REST APIs are built around resources, not actions. Resources are the nouns of your API.

Resource Identification

Good Resource URIs:

GET    /users                  # Collection
GET    /users/{id}             # Individual resource
GET    /users/{id}/orders      # Nested collection
POST   /users                  # Create resource
PUT    /users/{id}             # Replace resource
PATCH  /users/{id}             # Update resource
DELETE /users/{id}             # Delete resource

Bad Resource URIs:

POST   /getUser                # Verb in URI
POST   /createUser             # Verb in URI
GET    /user?action=delete     # Action as query param

Resource Naming Conventions

  • Use plural nouns for collections: /users, /orders, /products
  • Use lowercase and hyphens for readability: /shipping-addresses
  • Avoid deep nesting (max 2-3 levels): /users/{id}/orders/{orderId}
  • Use query parameters for filtering: /users?status=active&role=admin

HTTP Method Semantics

Safe and Idempotent Methods

MethodSafeIdempotentUse Case
GETYesYesRetrieve resource(s)
POSTNoNoCreate resource, non-idempotent operations
PUTNoYesReplace entire resource
PATCHNoNoPartial update
DELETENoYesRemove resource
HEADYesYesGet metadata only
OPTIONSYesYesGet allowed methods

Method Usage

GET - Retrieve Resources

GET /users/123
Accept: application/json

Response: 200 OK
{
  "id": 123,
  "name": "John Doe",
  "email": "john@example.com",
  "created_at": "2024-01-15T10:30:00Z"
}

POST - Create Resources

POST /users
Content-Type: application/json

{
  "name": "Jane Smith",
  "email": "jane@example.com"
}

Response: 201 Created
Location: /users/124
{
  "id": 124,
  "name": "Jane Smith",
  "email": "jane@example.com",
  "created_at": "2024-01-16T14:20:00Z"
}

PUT - Replace Resource

PUT /users/123
Content-Type: application/json

{
  "name": "John Doe Updated",
  "email": "john.new@example.com"
}

Response: 200 OK
{
  "id": 123,
  "name": "John Doe Updated",
  "email": "john.new@example.com",
  "updated_at": "2024-01-17T09:15:00Z"
}

PATCH - Partial Update

PATCH /users/123
Content-Type: application/json

{
  "email": "john.updated@example.com"
}

Response: 200 OK
{
  "id": 123,
  "name": "John Doe",
  "email": "john.updated@example.com",
  "updated_at": "2024-01-17T10:00:00Z"
}

DELETE - Remove Resource

DELETE /users/123

Response: 204 No Content

HTTP Status Codes

Success Codes (2xx)

  • 200 OK - Request succeeded (GET, PUT, PATCH)
  • 201 Created - Resource created (POST), include Location header
  • 202 Accepted - Request accepted for async processing
  • 204 No Content - Success with no response body (DELETE)

Redirection (3xx)

  • 301 Moved Permanently - Resource permanently moved
  • 302 Found - Temporary redirect
  • 304 Not Modified - Cached version is still valid

Client Errors (4xx)

  • 400 Bad Request - Invalid request syntax or validation error
  • 401 Unauthorized - Authentication required or failed
  • 403 Forbidden - Authenticated but not authorized
  • 404 Not Found - Resource doesn't exist
  • 405 Method Not Allowed - HTTP method not supported for resource
  • 409 Conflict - Request conflicts with current state (e.g., duplicate)
  • 422 Unprocessable Entity - Valid syntax but semantic errors
  • 429 Too Many Requests - Rate limit exceeded

Server Errors (5xx)

  • 500 Internal Server Error - Unexpected server error
  • 502 Bad Gateway - Invalid response from upstream server
  • 503 Service Unavailable - Server temporarily unavailable
  • 504 Gateway Timeout - Upstream server timeout

HATEOAS (Hypermedia)

Hypermedia-Driven APIs

Include links to related resources and available actions:

{
  "id": 123,
  "name": "John Doe",
  "email": "john@example.com",
  "_links": {
    "self": { "href": "/users/123" },
    "orders": { "href": "/users/123/orders" },
    "update": { "href": "/users/123", "method": "PATCH" },
    "delete": { "href": "/users/123", "method": "DELETE" }
  }
}

HAL (Hypertext Application Language)

{
  "id": 123,
  "name": "John Doe",
  "_links": {
    "self": { "href": "/users/123" }
  },
  "_embedded": {
    "orders": [
      {
        "id": 456,
        "total": 99.99,
        "_links": {
          "self": { "href": "/orders/456" }
        }
      }
    ]
  }
}

Content Negotiation

Accept Headers

GET /users/123
Accept: application/json

GET /users/123
Accept: application/xml

GET /users/123
Accept: application/hal+json

Response Content-Type

Content-Type: application/json; charset=utf-8
Content-Type: application/problem+json
Content-Type: application/hal+json

Idempotency

Idempotent Operations

PUT - Always idempotent: Multiple identical PUT requests produce the same result as a single request.

DELETE - Idempotent: First DELETE returns 204, subsequent DELETEs return 404 (same end state).

POST - Not idempotent by default: Use Idempotency-Key header for idempotent POST:

POST /payments
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

{
  "amount": 100.00,
  "currency": "USD"
}

Server stores idempotency key and returns same response for duplicate requests.

Cache Control

Cache Headers

Cache-Control: public, max-age=3600
Cache-Control: private, no-cache
Cache-Control: no-store
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Last-Modified: Wed, 15 Jan 2024 10:30:00 GMT

Conditional Requests

GET /users/123
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

Response: 304 Not Modified
PUT /users/123
If-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Content-Type: application/json

{
  "name": "Updated Name"
}

Response: 412 Precondition Failed (if ETag doesn't match)

URI Patterns

Consistent URI Structure

/{version}/{resource}
/{version}/{resource}/{id}
/{version}/{resource}/{id}/{sub-resource}
/{version}/{resource}/{id}/{sub-resource}/{sub-id}

Query Parameters

Filtering:

GET /users?status=active&role=admin
GET /products?category=electronics&price_min=100&price_max=500

Sorting:

GET /users?sort=created_at
GET /users?sort=-created_at          # Descending
GET /users?sort=name,created_at      # Multiple fields

Field Selection:

GET /users?fields=id,name,email
GET /users?exclude=password,social_security_number

Search:

GET /users?q=john
GET /products?search=laptop

Best Practices

  1. Use nouns, not verbs - Resources are nouns, methods are verbs
  2. Plural collections - Use /users not /user
  3. Consistent naming - Choose snake_case or camelCase and stick to it
  4. Proper status codes - Use appropriate HTTP status codes
  5. Include metadata - Pagination, filtering, sorting info in responses
  6. Version your API - Plan for evolution from day one
  7. Document everything - OpenAPI specs, examples, error codes
  8. Security by default - HTTPS, authentication, rate limiting
  9. Support filtering - Enable clients to get exactly what they need
  10. Implement HATEOAS - Make APIs self-documenting and discoverable