Skip to content
SP StackPractices
intermediate

REST API Design Guide

A comprehensive guide to designing clean, scalable, and maintainable REST APIs.

restapidesignhttparchitecturebest-practices

REST API Design Guide

Overview

REST (Representational State Transfer) is the dominant architectural style for designing networked applications. A well-designed REST API is predictable, self-descriptive, and easy to consume across multiple clients.

This guide covers the foundational principles and practical decisions that separate amateur APIs from production-grade ones.

When to Use

This guide applies when:

  • Building public or internal HTTP APIs
  • Designing microservice communication boundaries
  • Creating backend services consumed by web, mobile, or CLI clients
  • Migrating from RPC or SOAP to REST

Core Principles

1. Resources and URLs

A REST API is organized around resources — nouns, not actions:

Good (Resource)Bad (Action)
GET /usersGET /getUsers
POST /ordersPOST /createOrder
DELETE /posts/42DELETE /deletePost?id=42

Use plural nouns for collections and singular for specific instances:

GET    /users          # List all users
GET    /users/123      # Get user 123
POST   /users          # Create a new user
PUT    /users/123      # Replace user 123
PATCH  /users/123      # Partially update user 123
DELETE /users/123      # Remove user 123

2. HTTP Methods

MethodPurposeIdempotent
GETRetrieve a resourceYes
POSTCreate a resourceNo
PUTReplace a resourceYes
PATCHPartially updateYes (usually)
DELETERemove a resourceYes

3. Status Codes

Use the correct HTTP status code to communicate intent:

CodeMeaningWhen to Use
200 OKSuccessStandard response for successful requests
201 CreatedResource createdAfter a successful POST
204 No ContentEmpty successAfter a successful DELETE
400 Bad RequestClient errorInvalid input, validation failure
401 UnauthorizedNot authenticatedMissing or invalid credentials
403 ForbiddenNo permissionAuthenticated but not authorized
404 Not FoundMissing resourceURL or ID does not exist
409 ConflictState conflictDuplicate email, concurrent edit
422 UnprocessableSemantic errorValid JSON but invalid business logic
500 Internal ErrorServer errorUnexpected failure, log and report

Advanced Patterns

Versioning

Always version your API from day one:

/api/v1/users
/api/v2/users

Prefer URL versioning over headers for simplicity. Document the deprecation and sunset policy.

Pagination

For collection endpoints, never return unbounded lists:

{
  "data": [...],
  "pagination": {
    "page": 2,
    "per_page": 20,
    "total": 145,
    "total_pages": 8
  }
}

Use cursor-based pagination for high-churn data, offset-based for stable datasets.

GET /users?role=admin&sort=-created_at
GET /products?search=laptop&category=electronics

Use query parameters consistently. Document supported filters in your API docs.

Error Responses

Return a consistent error envelope:

{
  "error": {
    "code": "INVALID_EMAIL",
    "message": "The email format is invalid.",
    "field": "email",
    "documentation_url": "https://docs.example.com/errors/INVALID_EMAIL"
  }
}

Best Practices

  • Use JSON as the default content type (application/json)
  • Return consistent envelopes — wrap responses in a predictable structure
  • Support Content-Type and Accept headers properly
  • Implement rate limiting — protect your infrastructure and users
  • Use HTTPS everywhere — never expose APIs over plain HTTP
  • Document with OpenAPI — generate specs and interactive docs
  • Version from v1 — retroactive versioning is painful
  • Return Location headers on 201 Created responses

Common Mistakes

  • Using verbs in URLs/createUser breaks REST semantics
  • Returning 200 OK for errors — confuses clients and breaks retries
  • No pagination — endpoints that crash under real data load
  • Exposing internal IDs — use UUIDs or slug-based identifiers
  • Inconsistent naming — mixing camelCase and snake_case in JSON
  • Missing Content-Type handling — clients receive HTML error pages instead of JSON
  • No rate limiting — invites abuse and accidental DDoS
  • Tight coupling to database schema — leak implementation details

Frequently Asked Questions

Q: Should I use PUT or PATCH for updates? A: Use PUT for full replacements (client sends the complete resource) and PATCH for partial updates. If you only support one, document it clearly.

Q: How do I handle file uploads in a REST API? A: Use multipart/form-data for simple uploads. For large files, use presigned URLs (S3-style) or chunked upload endpoints.

Q: What is HATEOAS and do I need it? A: HATEOAS (Hypermedia as the Engine of Application State) includes links in responses. It is nice-to-have for public APIs but overkill for internal services.

Q: How do I authenticate a REST API? A: For server-to-server, use API keys or OAuth 2.0 client credentials. For user-facing apps, use OAuth 2.0 with PKCE or session-based auth with CSRF protection.