A well-designed REST API is a joy to consume. A poorly designed one generates a constant stream of support tickets, client bugs, and integration headaches. The difference lies in applying a set of consistent, time-tested best practices that make your API intuitive, predictable, and maintainable. This guide covers the principles used by world-class APIs like Stripe, GitHub, and Twilio.

1. Use Nouns for Resources, Not Verbs

REST is resource-oriented. URLs should identify things (nouns), not actions (verbs). The HTTP method (GET, POST, PUT, DELETE) communicates the action:

Nouns vs Verbs in URLs
# ❌ Verb-based URLs (RPC style)
GET  /getUser?id=42
POST /createUser
POST /deleteUser?id=42
POST /updateUserEmail

# ✅ Noun-based URLs (REST style)
GET    /users/42          # Retrieve user 42
POST   /users             # Create a new user
DELETE /users/42          # Delete user 42
PATCH  /users/42          # Update specific fields of user 42

2. Use Plural Nouns for Collection Endpoints

Always use plural nouns for resource collections. This is consistent and more natural when reading the URL — /users returns a collection of users, and /users/42 returns a single user:

Collection and Resource Endpoints
GET    /articles          # List all articles
POST   /articles          # Create a new article
GET    /articles/slug     # Get a specific article
PUT    /articles/slug     # Replace an article entirely
PATCH  /articles/slug     # Update specific fields of an article
DELETE /articles/slug     # Delete an article

3. Use HTTP Methods Correctly

Use the semantically correct HTTP method for each operation:

  • GET — Retrieve data. Must be safe (no side effects) and idempotent (calling it multiple times returns the same result).
  • POST — Create a new resource. Not idempotent — calling it twice creates two resources.
  • PUT — Replace an entire resource with the provided data. Idempotent.
  • PATCH — Partially update a resource (send only the fields that changed). Not required to be idempotent.
  • DELETE — Remove a resource. Idempotent — deleting an already-deleted resource should return 404, not an error.

4. Return Correct HTTP Status Codes

HTTP status codes communicate the result of an operation without the client needing to parse the response body. Using the wrong status code forces clients to implement extra logic and undermines the semantics of HTTP:

Essential Status Codes
200 OK              # Successful GET, PATCH, DELETE
201 Created         # Successful POST (return the created resource)
204 No Content      # Successful DELETE (no body to return)
400 Bad Request     # Invalid request syntax or validation error
401 Unauthorized    # Missing or invalid authentication credentials
403 Forbidden       # Authenticated but not authorised for this resource
404 Not Found       # Resource does not exist
409 Conflict        # Conflict with current state (e.g., duplicate email)
422 Unprocessable   # Valid syntax but semantic validation failed
429 Too Many Requests  # Rate limit exceeded
500 Internal Server Error  # Unexpected server-side error

Never return 200 OK with an error message in the body. If something went wrong, return an appropriate 4xx or 5xx status code.

5. Design Consistent Error Responses

Every error response should follow the same structure so clients can handle errors generically:

Consistent Error Response Structure
{
  "error": {
    "status": 422,
    "code": "VALIDATION_ERROR",
    "message": "The request data is invalid.",
    "details": [
      {
        "field": "email",
        "message": "Must be a valid email address."
      },
      {
        "field": "password",
        "message": "Must be at least 8 characters long."
      }
    ]
  }
}

6. Version Your API from Day One

APIs evolve. You will need to make breaking changes. If you don't version your API from the start, any breaking change will immediately break all existing integrations. The most common versioning strategies:

  • URL versioning (most common): /api/v1/users, /api/v2/users — Simple, explicit, and easy to test in a browser.
  • Header versioning: Accept: application/vnd.myapi.v2+json — Keeps URLs clean but harder to test and cache.
  • Query parameter: /api/users?version=2 — Simple but non-standard.

URL versioning is recommended for most public APIs due to its simplicity and visibility. Increment the version number (v1 → v2) only for breaking changes. Additive changes (new fields, new endpoints) are not breaking changes.

7. Implement Pagination for Collections

Never return an unbounded list of resources. Always paginate collection endpoints and return pagination metadata in the response:

Cursor-Based Pagination Response
{
  "data": [
    { "id": "usr_abc123", "name": "Alice" },
    { "id": "usr_def456", "name": "Bob" }
  ],
  "pagination": {
    "total": 847,
    "page": 1,
    "per_page": 20,
    "next_cursor": "usr_def456",
    "has_more": true
  }
}

Cursor-based pagination (using the ID of the last item as a cursor) is preferred over offset pagination for large datasets because it remains consistent even when records are added or deleted between page requests.

8. Use HTTPS — Always

Every API should be served exclusively over HTTPS. This is non-negotiable. HTTP transmits all data — including authentication tokens, passwords, and sensitive user data — in plaintext that anyone on the network can read and modify.

9. Implement Rate Limiting and Return Rate Limit Headers

Rate limiting protects your API from abuse and ensures fair usage. Communicate the current rate limit state to clients via standard headers:

Rate Limit Headers
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 734
X-RateLimit-Reset: 1718481600

When a client exceeds the rate limit, return 429 Too Many Requests with a Retry-After header indicating when they can retry.

10. Document Your API Thoroughly

An undocumented API is essentially unusable for external developers. Use the OpenAPI Specification (OAS, formerly Swagger) to document your API endpoints — it's an industry standard that enables automatic generation of interactive documentation, client SDKs, and API testing tools.

Work with JSON API Data Instantly

Format API responses for debugging or compress JSON payloads for production with our free tools.