REST API Design Reference

REST API design reference — HTTP methods, status codes, URL conventions, versioning, pagination, error responses. CRUD to resource mapping. Best practices with examples.

7 min read

What it is

A reference for designing RESTful APIs using common conventions and best practices.

Installation

This is a conceptual reference, not a software tool. No installation required.

Core Concepts

  • Resources: The fundamental entities your API exposes (e.g., users, products, orders). They are identified by URIs.
  • URIs (Uniform Resource Identifiers): The unique addresses for resources. Typically use nouns, not verbs, and are plural.
  • HTTP Methods (Verbs): Define the action to be performed on a resource. The most common are:
    • GET: Retrieve a resource or collection of resources.
    • POST: Create a new resource.
    • PUT: Update an existing resource (replace entirely).
    • PATCH: Partially update an existing resource.
    • DELETE: Remove a resource.
  • HTTP Status Codes: Indicate the outcome of an API request. Key categories:
    • 2xx (Success): 200 OK, 201 Created, 204 No Content.
    • 3xx (Redirection): 301 Moved Permanently, 304 Not Modified.
    • 4xx (Client Error): 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict.
    • 5xx (Server Error): 500 Internal Server Error, 503 Service Unavailable.
  • Request/Response Bodies: Typically JSON, used to send data to the API (request) and receive data from it (response).
  • Headers: Provide metadata about the request or response (e.g., Content-Type, Authorization, Accept).
  • Idempotence: An operation is idempotent if making it multiple times has the same effect as making it once. GET, PUT, and DELETE are typically idempotent. POST and PATCH are generally not.

Commands / Usage

Resource Identification (URIs)

  • /users
    • Represents the collection of all users.
  • /users/123
    • Represents a specific user with ID 123.
  • /users/123/orders
    • Represents the collection of orders belonging to user 123.
  • /users/123/orders/456
    • Represents a specific order with ID 456 belonging to user 123.
  • /products
    • Represents the collection of all products.
  • /products/abc-789
    • Represents a specific product with a human-readable ID abc-789.

HTTP Methods (Actions on Resources)

Retrieving Resources (GET)

  • GET /users
    • Retrieve a list of all users.
  • GET /users?status=active&limit=10
    • Retrieve a list of active users, with a maximum of 10 results.
  • GET /users/123
    • Retrieve details for the user with ID 123.
  • GET /users/123/orders
    • Retrieve a list of orders for user 123.
  • GET /products/abc-789
    • Retrieve details for the product with ID abc-789.
  • GET /products?category=electronics&sort=price_desc
    • Retrieve a list of electronics products, sorted by price in descending order.

Creating Resources (POST)

  • POST /users
    • Create a new user. The request body contains the user’s details.
    • Example Request Body:
      {
        "username": "jane.doe",
        "email": "jane.doe@example.com"
      }
      
    • Expected Response: 201 Created with the URI of the new resource in the Location header and the new resource’s details in the body.
  • POST /users/123/orders
    • Create a new order for user 123. The request body contains order details.
    • Example Request Body:
      {
        "items": [
          {"productId": "abc-789", "quantity": 2},
          {"productId": "def-456", "quantity": 1}
        ],
        "shippingAddress": "123 Main St"
      }
      
    • Expected Response: 201 Created with the URI of the new order.

Updating Resources (PUT - Full Replacement)

  • PUT /users/123
    • Replace the entire user resource with ID 123 with the data provided in the request body.
    • Example Request Body:
      {
        "username": "jane.doe.updated",
        "email": "jane.doe.new@example.com",
        "status": "inactive"
      }
      
    • Expected Response: 200 OK with the updated resource, or 204 No Content if no body is returned.
  • PUT /products/abc-789
    • Replace the entire product resource abc-789.

Partially Updating Resources (PATCH)

  • PATCH /users/123
    • Partially update the user resource with ID 123. Only the fields provided in the request body are modified.
    • Example Request Body:
      {
        "status": "active"
      }
      
    • Expected Response: 200 OK with the updated resource, or 204 No Content.
  • PATCH /products/abc-789
    • Partially update the product resource abc-789.

Deleting Resources (DELETE)

  • DELETE /users/123
    • Delete the user resource with ID 123.
    • Expected Response: 204 No Content on successful deletion.
  • DELETE /users/123/orders/456
    • Delete the specific order 456 for user 123.
    • Expected Response: 204 No Content.

Filtering, Sorting, and Pagination (Query Parameters)

  • GET /products?category=electronics
    • Filter products by category.
  • GET /products?in_stock=true
    • Filter products that are in stock.
  • GET /users?sort=lastName_asc
    • Sort users by last name in ascending order.
  • GET /users?sort=createdAt_desc
    • Sort users by creation date in descending order.
  • GET /products?limit=20
    • Limit the number of results to 20.
  • GET /products?offset=40&limit=20
    • Paginate results: skip the first 40 products and return the next 20.
  • GET /products?page=3&pageSize=10
    • Alternative pagination: retrieve the 3rd page of results with 10 items per page.

Request Headers

  • Content-Type: application/json
    • Indicates that the request body is in JSON format.
  • Accept: application/json
    • Indicates that the client expects a JSON response.
  • Authorization: Bearer your_access_token
    • Provides authentication credentials (e.g., OAuth 2.0).
  • If-None-Match: "etag-value"
    • Used for caching; the server returns 304 Not Modified if the resource hasn’t changed since the etag-value was generated.

Response Headers

  • Content-Type: application/json
    • Indicates the response body is in JSON format.
  • Location: /users/123
    • Returned with 201 Created to provide the URI of the newly created resource.
  • ETag: "etag-value"
    • An identifier for a specific version of a resource, used for caching.
  • Cache-Control: max-age=3600
    • Instructs clients on how long to cache the response.

Error Handling

  • GET /users/999 (if user 999 does not exist)
    • Response: 404 Not Found
    • Response Body:
      {
        "error": "User not found",
        "code": "USER_NOT_FOUND"
      }
      
  • POST /users (with invalid data)
    • Response: 400 Bad Request
    • Response Body:
      {
        "error": "Invalid email format",
        "field": "email",
        "code": "INVALID_INPUT"
      }
      
  • POST /users (if username already exists)
    • Response: 409 Conflict
    • Response Body:
      {
        "error": "Username already taken",
        "code": "USERNAME_TAKEN"
      }
      

Common Patterns

Creating a resource and immediately retrieving it

# Create a new user
curl -X POST -H "Content-Type: application/json" -d '{"username": "testuser", "email": "test@example.com"}' http://api.example.com/users

# Assuming the response was 201 Created with Location: /users/456
# Retrieve the newly created user
curl http://api.example.com/users/456

Updating a resource and verifying the change

# Update user 123's status
curl -X PATCH -H "Content-Type: application/json" -d '{"status": "inactive"}' http://api.example.com/users/123

# Verify the update by fetching the user
curl http://api.example.com/users/123

Handling collections with pagination

# Get the first 10 products
curl "http://api.example.com/products?limit=10"

# Get the next 10 products
curl "http://api.example.com/products?offset=10&limit=10"

Filtering and sorting a collection

# Get all active users, sorted by their last name
curl "http://api.example.com/users?status=active&sort=lastName_asc"

Gotchas

  • Plural vs. Singular Nouns: Always use plural nouns for resource collections (e.g., /users, not /user). Use singular for specific resources (e.g., /users/123).
  • Verbs in URIs: Avoid verbs in URIs. HTTP methods (GET, POST, PUT, PATCH, DELETE) define the action. /getUser is bad; GET /users/{id} is good.
  • HTTP Method Misuse: POST should be for creating resources. Using POST to update or retrieve is incorrect. PUT replaces an entire resource; PATCH modifies parts of it. Using PUT when you only intend to change one field can lead to unintended data loss if other fields are not included in the request.
  • Status Code Accuracy: Ensure you return the correct HTTP status code. Returning 200 OK for a resource that wasn’t found (404) or for a failed creation (400, 409) is misleading.
  • JSON Structure Consistency: Maintain a consistent JSON structure for request and response bodies. Use clear, descriptive key names.
  • Error Response Standardization: Define a standard format for error responses, including a human-readable message, an error code, and potentially details about the specific field causing the error.
  • Case Sensitivity: URIs are generally case-sensitive, although web servers might sometimes normalize them. Stick to lowercase for consistency. Query parameter names and values can also be case-sensitive depending on server implementation.
  • Idempotence: Be aware of which methods are idempotent. Repeatedly sending a POST request will likely create multiple resources, whereas repeated PUT or DELETE requests should have the same effect as a single request.
  • HATEOAS (Hypermedia as the Engine of Application State): While not strictly required for all REST APIs, including links in responses to guide clients to related actions or resources is a hallmark of mature RESTful design.