Skip to main content
Ordinary Utils Fast, free tools that respect your time.

REST API Design Principles

Building intuitive, consistent, and maintainable APIs.

Web Development 13 min read Last updated: June 19, 2026

What is REST?

REST (Representational State Transfer) is an architectural style for designing networked applications. It uses standard HTTP methods and status codes, making APIs intuitive for developers who understand HTTP.

A RESTful API treats data as "resources" accessed via URLs, manipulated using HTTP methods (GET, POST, PUT, DELETE). Good REST design creates APIs that are predictable, consistent, and easy to use.

Resource Naming

URLs should identify resources (nouns), not actions (verbs). The HTTP method indicates the action.

Avoid
/getUsers
/createUser
/deleteUser/123
/getUserOrders
Prefer
GET /users
POST /users
DELETE /users/123
GET /users/123/orders

Naming Conventions

  • Plural nouns: /users not /user
  • Lowercase: /users not /Users
  • Hyphens for readability: /user-profiles not /userProfiles
  • No trailing slashes: /users not /users/
  • No file extensions: /users not /users.json

HTTP Methods

Method Purpose Idempotent Safe
GET Retrieve resources Yes Yes
POST Create new resources No No
PUT Replace entire resource Yes No
PATCH Partial update No* No
DELETE Remove resource Yes No

*PATCH can be idempotent depending on implementation.

Example CRUD Operations

GET    /users          # List all users
GET    /users/123      # Get user 123
POST   /users          # Create new user
PUT    /users/123      # Replace user 123 entirely
PATCH  /users/123      # Update specific fields of user 123
DELETE /users/123      # Delete user 123

Request and Response Format

Consistent JSON Structure

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

// Collection
{
  "data": [
    { "id": 1, "name": "John Doe" },
    { "id": 2, "name": "Jane Smith" }
  ],
  "meta": {
    "total": 100,
    "page": 1,
    "per_page": 20
  }
}

Error Responses

{
  "error": {
    "code": "validation_error",
    "message": "The request data is invalid",
    "details": {
      "email": ["Invalid email format"],
      "password": ["Must be at least 8 characters"]
    }
  }
}

Status Codes

// Success
200 OK           # Successful GET, PUT, PATCH
201 Created      # Successful POST (include Location header)
204 No Content   # Successful DELETE

// Client Errors
400 Bad Request  # Malformed request
401 Unauthorized # Missing or invalid authentication
403 Forbidden    # Authenticated but not authorized
404 Not Found    # Resource doesn't exist
422 Unprocessable # Validation errors

// Server Errors
500 Internal Server Error  # Unexpected error

Filtering, Sorting, and Pagination

Filtering

GET /users?status=active
GET /users?role=admin&status=active
GET /orders?created_after=2024-01-01
GET /products?price_min=10&price_max=100

Sorting

GET /users?sort=created_at        # Ascending
GET /users?sort=-created_at       # Descending (prefix with -)
GET /users?sort=name,-created_at  # Multiple fields

Pagination

// Page-based
GET /users?page=2&per_page=20

// Cursor-based (better for large datasets)
GET /users?cursor=abc123&limit=20

// Response includes pagination meta
{
  "data": [...],
  "meta": {
    "total": 1000,
    "page": 2,
    "per_page": 20,
    "total_pages": 50
  },
  "links": {
    "first": "/users?page=1",
    "prev": "/users?page=1",
    "next": "/users?page=3",
    "last": "/users?page=50"
  }
}

Nested Resources

Express relationships through URL structure:

GET /users/123/orders          # Orders belonging to user 123
GET /users/123/orders/456      # Specific order of user 123
POST /users/123/orders         # Create order for user 123

GET /posts/123/comments        # Comments on post 123
POST /posts/123/comments       # Add comment to post 123

Guidelines

  • Limit nesting to 2-3 levels maximum
  • If resources can exist independently, don't nest
  • Use query parameters for optional relationships

API Versioning

URL Path (Most Common)

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

Header-based

Accept: application/vnd.api+json; version=1

Query Parameter

/api/users?version=1

URL versioning is most visible and commonly used. Version when making breaking changes (removing fields, changing response structure).

Authentication

Bearer Tokens (JWT)

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

API Keys

// Header
X-API-Key: your-api-key

// Query parameter (less secure, visible in logs)
/api/users?api_key=your-api-key

Best Practices

  • Always use HTTPS
  • Prefer headers over query parameters for credentials
  • Implement rate limiting
  • Use short-lived access tokens with refresh tokens

HATEOAS

Hypermedia as the Engine of Application State—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" }
  }
}

HATEOAS makes APIs more discoverable but adds complexity. It's optional for most APIs.

Documentation

Good documentation is essential. Include:

  • Authentication methods
  • All endpoints with HTTP methods
  • Request/response examples
  • Error codes and messages
  • Rate limits
  • Changelog

Tools like OpenAPI (Swagger) can generate interactive documentation from your API specification.

Best Practices Summary

  • Use nouns for URLs, HTTP methods for actions
  • Return appropriate status codes
  • Use consistent JSON response structure
  • Version your API from the start
  • Implement pagination for list endpoints
  • Support filtering and sorting
  • Always use HTTPS
  • Provide comprehensive documentation
  • Return helpful error messages
  • Implement rate limiting

Format API Responses

Use our JSON formatter to beautify and validate your API response payloads.

Open JSON Formatter →