# REST API Design Best Practices

# Core Principles

* Design APIs that are:
    
    1. Easy to read and work with
        
    2. Hard to misuse
        
    3. Complete and concise
        

# Naming and URL Structure

## Resource Naming

* Use nouns to represent resources, not verbs
    
    * Good: `/items`, `/employees`
        
    * Bad: `/createItems`, `/getEmployees`
        
* Use plural nouns for collections (e.g., `/orders` not `/order`)
    
* Use hyphens for readability (e.g., `inventory-management`) instead of underscores
    

## URL Structure

* Implement logical grouping for nested resources
    
    * Example: `/customers/{id}/orders`
        
* Avoid going deeper than collection/resource/collection
    
* Don't mirror database structure in URLs to prevent exposing unnecessary information
    

# Versioning

* Always version your APIs to prevent breaking changes
    
* Options:
    
    1. Path versioning: `/v1/store`, `/v2/store` (more common)
        
    2. Query parameter: `?version=2`
        

# Data Handling

## Pagination

* Implement pagination for large datasets
    
* Use cursor based pagination (more efficient, similar to what stripe does)
    
    * Edit: Offset based is better for experiences where you want pages e.g. search in a booking system.
        
* Example: `/items?lastItemId=1000&limit=20`
    

## Filtering and Sorting

* Allow filtering through query parameters
    
    * Example: `/users?lastName=Smith&age=30`
        
* Support field selection to limit response data
    
    * Example: `/products?fields=id,name,price`
        
    * Can be faster since less data needs to be fetched from the database and serialised before sending over the network
        
* Enable sorting with clear parameters
    
    * Example: `/posts?sort=+author,-datePublished`
        

# API Operations

## Idempotency

* Ensure operations are idempotent where appropriate
    
* Multiple identical requests should result in the same state
    
* Particularly important for DELETE, PUT operations
    
* For sensitive operations, consider using idempotency keys. [Stripe does this for charge operations.](https://docs.stripe.com/api/idempotent_requests)
    

## Async Operations

* Use status code 202 for long-running operations, says the operation is accepted but not completed
    
* Provide status endpoint for tracking progress e.g. `GET /orders/123/status`
    
* Include status endpoint URL in Location header (e.g. `Location: /orders/123/status`), helps clients to know where to get the status of the operation. This follows the HATEOAS principle (Hypermedia as the Engine of Application State) which states that the API should tell the client what it can do next.
    
* Consider supporting operation cancellation e.g. `DELETE /orders/123/cancel`
    

## Partial Responses

Support [partial content](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206) retrieval for large resources e.g. video files. This is useful for large files that you don't want to download all at once, think Netflix movies... They would be HUGE if you downloaded the whole thing at once.

1. First, client can make a HEAD request to check resource size (very fast request, no body needed):
    

```javascript
HEAD /files/big-video.mp4
Response headers:
Accept-Ranges: bytes
Content-Length: 100000000
Content-Type: video/mp4
```

2. Then client can request specific chunks using Range header:
    

```javascript
GET /files/big-video.mp4
Range: bytes=0-1048575  # Request first 1MB
```

3. Server responds with partial content:
    

```javascript
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1048575/100000000
Content-Length: 1048576
[... first 1MB of data ...]
```

4. Client can request next chunk:
    

```javascript
GET /files/big-video.mp4
Range: bytes=1048576-2097151  # Request second 1MB
```

# Security

* Implement SSL/TLS encryption -&gt; Use HTTPS.
    
* Use proper authentication and authorization -&gt; OAuth, JWT, etc.
    
* Apply rate limiting to prevent DoS attacks
    
* Be careful with error messages to avoid information leakage -&gt; Best to always craft a good error message: No inner details, clear what's wrong and what to do next.
    

# Error Handling

* Return appropriate HTTP status codes
    
* Provide clear error messages
    
* Include enough information for debugging without exposing sensitive details
    
* Use 204 for successful empty responses
    

# Documentation

* Use OpenAPI (formerly Swagger) for API documentation
    
* Document:
    
    * Endpoint structure
        
    * Request/response formats
        
    * Authentication requirements
        
    * Error codes and messages
        

## HATEOAS (Hypermedia as the Engine of Application State)

* Consider implementing [HATEOAS](https://en.wikipedia.org/wiki/HATEOAS) for better API navigation
    
* Include related resource links in responses, you can also include `self` links, they would describe other things you can do with the resource. If you created a post, they would include links to edit the post, delete the post, etc.
    

Example:

```json
{
  "orderId": "12345",
  "status": "pending",
  "total": 99.99,
  "links": {
    "self": {
      "href": "/orders/12345",
      "method": "GET"
    },
    "update": {
      "href": "/orders/12345",
      "method": "PUT"
    },
    "cancel": {
      "href": "/orders/12345/cancel",
      "method": "POST"
    },
    "payment": {
      "href": "/orders/12345/payment",
      "method": "POST"
    },
    "customer": {
      "href": "/customers/789",
      "method": "GET"
    }
  }
}
```

For each method, you provide the type of operation PLUS href and method for each operation.

Each thing should be self documenting. For POST with body, you can include contentType and schema, example:

```json
    "create": {
      "href": "/orders",
      "method": "POST",
      "contentType": "application/json",
      "schema": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array"
          }
        }
      }
    }
```
