PureTools

REST API Design: Naming, Pagination, Errors, and Versioning

PureTools Team· 8 min read
REST API Design: Naming, Pagination, Errors, and Versioning

REST API Design: Make It Obvious

A good API is one that a developer can guess. If they need /users, GET /users should work. If they need user 42, GET /users/42 should work. When APIs follow consistent patterns, documentation becomes optional for common operations.

Resource Naming

DoDon'tWhy
GET /usersGET /getUsersThe HTTP method is the verb
GET /users/42GET /user/42Collections are plural
POST /usersPOST /createUserPOST already means "create"
GET /users/42/ordersGET /getUserOrders?userId=42Nested resources show relationships
kebab-case in URLscamelCase or snake_caseURLs are case-insensitive by convention

HTTP Methods

GET    /users          → List users
GET    /users/42       → Get user 42
POST   /users          → Create a user (body has data)
PUT    /users/42       → Replace user 42 entirely
PATCH  /users/42       → Update specific fields of user 42
DELETE /users/42       → Delete user 42

Pagination

Offset-based (simple, most common):

GET /users?page=2&limit=20

{
  "data": [...],
  "meta": {
    "page": 2,
    "limit": 20,
    "total": 156,
    "total_pages": 8
  }
}

Cursor-based (better for large datasets, real-time data):

GET /users?cursor=eyJpZCI6NDJ9&limit=20

{
  "data": [...],
  "meta": {
    "next_cursor": "eyJpZCI6NjJ9",
    "has_more": true
  }
}

Error Responses

Be consistent. Pick a format and stick with it:

// Standard error format
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "field": "email",
        "message": "Must be a valid email address"
      },
      {
        "field": "age",
        "message": "Must be at least 18"
      }
    ]
  }
}

Always include: machine-readable error code, human-readable message, and field-level details for validation errors.

Versioning

StrategyExamplePros/Cons
URL path/api/v1/usersSimple, explicit, easy to route. Most common.
HeaderAccept: application/vnd.api+json;version=1Clean URLs, harder to test in browser.
Query param/users?version=1Easy to add, clutters query string.

URL path versioning wins for simplicity. Version only when you have breaking changes.

Filtering, Sorting, and Fields

// Filtering
GET /users?role=admin&status=active

// Sorting
GET /users?sort=-created_at,name   // - prefix = descending

// Sparse fields (return only what's needed)
GET /users?fields=id,name,email

// Search
GET /users?q=john

Authentication

// Bearer token (most common for APIs)
GET /users HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

// API key (for server-to-server)
GET /users HTTP/1.1
X-API-Key: sk_live_abc123

API reference tool: HTTP Status Codes — pick the right status code for every response.