REST API Best Practices

Design patterns and guidelines for building scalable, maintainable APIs

URL Design

Well-designed URLs are intuitive, predictable, and follow REST conventions.

๐Ÿ”— Use Nouns for Resources

URLs should represent resources (things), not actions. Use HTTP methods to define the action.

โœ… Good GET /users - Get all users
GET /users/123 - Get user 123
POST /users - Create a user
DELETE /users/123 - Delete user 123
โŒ Bad GET /getUsers
POST /createUser
GET /deleteUser/123
POST /users/delete

๐Ÿ“ Use Plural Nouns

Consistently use plural nouns for resource collections, even when accessing a single resource.

โœ… Good /users
/users/123
/products
/orders/456/items
โŒ Bad /user
/user/123
/product
/order/456/item

๐Ÿ—๏ธ Use Kebab-Case

Use lowercase letters and hyphens for multi-word resource names.

โœ… Good /user-profiles
/order-items
/api-keys
โŒ Bad /userProfiles
/UserProfiles
/user_profiles

๐Ÿ”„ Use Hierarchical Relationships

Express relationships between resources through URL hierarchy.

โœ… Good GET /users/123/orders - User's orders
GET /orders/456/items - Order's items
GET /posts/789/comments - Post's comments
โŒ Bad GET /getOrdersByUser?userId=123
GET /orderItems?orderId=456

API Versioning

Version your APIs to allow evolution without breaking existing clients. See our comprehensive versioning guide for detailed strategies.

URL Path Versioning

Include the version in the URL path. Most explicit and widely used approach.

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

Pros: Clear, cacheable, easy to implement

Cons: Not technically RESTful (versions aren't resources)

Header Versioning

Use a custom header to specify the API version.

GET /api/users
API-Version: 2

Pros: Clean URLs, more RESTful

Cons: Less visible, harder to test in browser

Query Parameter Versioning

Pass the version as a query parameter.

GET /api/users?version=2

Pros: Easy to add, explicit

Cons: Can be omitted, caching issues

Accept Header Versioning

Use content negotiation with the Accept header.

GET /api/users
Accept: application/vnd.api.v2+json

Pros: Most RESTful approach

Cons: Complex, easy to get wrong

Pagination

Always paginate large collections to improve performance and usability. See our pagination guide for cursor, offset, and keyset strategies.

Offset-Based Pagination

Use page and limit (or offset) parameters.

GET /api/users?page=2&limit=20
{
  "data": [...],
  "pagination": {
    "page": 2,
    "limit": 20,
    "total": 150,
    "total_pages": 8,
    "has_next": true,
    "has_prev": true
  },
  "links": {
    "self": "/api/users?page=2&limit=20",
    "first": "/api/users?page=1&limit=20",
    "prev": "/api/users?page=1&limit=20",
    "next": "/api/users?page=3&limit=20",
    "last": "/api/users?page=8&limit=20"
  }
}

Pros: Simple, allows jumping to any page

Cons: Performance degrades with large offsets, inconsistent with data changes

Cursor-Based Pagination

Use an opaque cursor for more efficient pagination.

GET /api/users?cursor=eyJpZCI6MTAwfQ&limit=20
{
  "data": [...],
  "pagination": {
    "limit": 20,
    "has_more": true,
    "next_cursor": "eyJpZCI6MTIwfQ",
    "prev_cursor": "eyJpZCI6ODB9"
  }
}

Pros: Consistent performance, handles real-time data

Cons: Can't jump to arbitrary pages

Filtering, Sorting & Field Selection

๐Ÿ” Filtering

Use query parameters for filtering resources.

GET /api/users?status=active&role=admin&created_after=2023-01-01

For complex queries, consider:

  • ?filter[status]=active - Bracketed notation
  • ?q=search+term - Full-text search
  • ?price_gte=100&price_lte=500 - Range filters

๐Ÿ“Š Sorting

Use a sort parameter with field names and direction.

GET /api/users?sort=-created_at,name

Common conventions:

  • sort=name - Ascending by name
  • sort=-name - Descending by name (minus prefix)
  • sort=name:asc - Explicit direction
  • sort=-created_at,name - Multiple fields

๐Ÿ“‹ Field Selection (Sparse Fieldsets)

Allow clients to request only specific fields to reduce payload size.

GET /api/users?fields=id,name,email
{
  "data": [
    {"id": 1, "name": "John", "email": "john@example.com"},
    {"id": 2, "name": "Jane", "email": "jane@example.com"}
  ]
}

Error Handling

Consistent error responses help clients understand and handle failures gracefully. See our error handling guide for standard formats and best practices.

Standard Error Response Format

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The request could not be validated",
    "details": [
      {
        "field": "email",
        "code": "INVALID_FORMAT",
        "message": "Email must be a valid email address"
      },
      {
        "field": "age",
        "code": "OUT_OF_RANGE",
        "message": "Age must be between 18 and 120"
      }
    ],
    "request_id": "abc123-def456",
    "timestamp": "2023-06-20T14:30:00Z",
    "documentation_url": "https://api.example.com/docs/errors#VALIDATION_ERROR"
  }
}

๐ŸŽฏ Use Appropriate Status Codes

Match HTTP status codes to error types. 4xx for client errors, 5xx for server errors.

๐Ÿ“ Provide Actionable Messages

Error messages should help developers understand what went wrong and how to fix it.

๐Ÿ”— Include Documentation Links

Link to relevant documentation for common errors to help developers resolve issues quickly.

๐Ÿ” Include Request IDs

Return a unique request ID for tracking and debugging purposes.

Authentication & Security

๐Ÿ”‘ API Keys

Simple authentication for server-to-server communication.

X-API-Key: your-api-key-here

Best for: Public APIs, simple integrations

๐ŸŽซ JWT (Bearer Tokens)

Self-contained tokens for stateless authentication.

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Best for: User authentication, mobile apps

๐Ÿ” OAuth 2.0

Industry standard for delegated authorization.

Best for: Third-party integrations, user consent flows

Security Best Practices

๐Ÿ”’ Always Use HTTPS

Never transmit sensitive data over plain HTTP. Enforce HTTPS everywhere.

โฑ๏ธ Rate Limiting

Protect your API from abuse with rate limits. Return 429 when exceeded.

โœ… Input Validation

Validate all input data. Never trust client input.

๐Ÿ›ก๏ธ CORS Configuration

Configure CORS headers appropriately for browser clients.

Response Design

๐Ÿ“ฆ Consistent Response Envelope

Wrap responses in a consistent structure.

// Success response
{
  "data": {...},
  "meta": {
    "request_id": "abc123",
    "timestamp": "2023-06-20T14:30:00Z"
  }
}

// Collection response
{
  "data": [...],
  "pagination": {...},
  "meta": {...}
}

// Error response
{
  "error": {...}
}

๐Ÿ• Use ISO 8601 for Dates

Always use ISO 8601 format with timezone for dates.

โœ… Good "2023-06-20T14:30:00Z"
"2023-06-20T14:30:00+02:00"
โŒ Bad "June 20, 2023"
"20/06/2023"
1687271400 (Unix timestamp without context)

๐Ÿ Use camelCase or snake_case Consistently

Pick one naming convention and stick with it throughout your API.

โœ… snake_case {"user_id": 1, "created_at": "..."}
โœ… camelCase {"userId": 1, "createdAt": "..."}
โŒ Mixed {"userId": 1, "created_at": "..."}

Documentation

Good documentation is essential for API adoption and developer experience.

๐Ÿ“– OpenAPI/Swagger

Use OpenAPI specification to document your API. It enables automated documentation, client generation, and testing.

๐Ÿ’ก Include Examples

Provide complete request and response examples for every endpoint.

๐Ÿงช Interactive Testing

Allow developers to test API calls directly from the documentation.

๐Ÿ“ Keep It Updated

Documentation should be versioned and updated alongside your API code.