🔌Developer

REST API Design: The Decisions That Come Back to Haunt You

The design choices that seem minor when building but cause months of pain later. Naming conventions, versioning, error formats, pagination — the real decisions.

8 min readJanuary 18, 2026By FreeToolKit TeamFree to read

API design decisions seem abstract until you're explaining to ten client teams why the /user endpoint inconsistently returns snake_case sometimes and camelCase other times. Here are the choices that feel small and aren't.

URL Structure: Rules Worth Following

  • Resources are nouns, never verbs: /users, /orders, /products — not /getUsers, /createOrder. The HTTP method (GET, POST, PUT, DELETE) is the verb.
  • Hierarchical relationships in the path: /users/123/orders returns orders for user 123. Don't go deeper than 3 levels — /users/123/orders/456/items is the maximum reasonable nesting.
  • Lowercase, hyphen-separated: /payment-methods not /PaymentMethods or /payment_methods. Uppercase in URLs is technically valid but a persistent source of confusion.
  • Filters and search go in query params: GET /users?status=active&role=admin not GET /users/active/admin.

The Error Response Format Matters More Than Most APIs Treat It

Every API invents its own error format. The result: every client has to parse differently. Consider RFC 7807 (Problem Details for HTTP APIs) — a standard format that's gaining adoption:

RFC 7807 error format

{
  "type": "https://api.example.com/errors/validation",
  "title": "Validation Failed",
  "status": 422,
  "detail": "The email field is required",
  "errors": [
    {"field": "email", "message": "Required"}
  ]
}

Authentication: Don't Invent Your Own

API key in Authorization header (Authorization: Bearer API_KEY) for simple cases. OAuth 2.0 for anything involving user permission delegation. JWT for stateless user authentication. The temptation to invent a custom auth scheme is real and almost always wrong — established patterns have known security properties; custom schemes have unknown ones.

The Versioning Decision Tree

Public API with external consumers: version from day one in the URL (/v1/). Internal API where you control all consumers: you can avoid versioning if you deploy clients and server together. Start adding versioning as soon as you have any external consumer or can't coordinate deploys. The cost of adding versioning later is high; the cost of including it from the start is low.

Rate Limiting: Document It, Communicate It

Return rate limit info in response headers, not just 429 errors: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. Clients need this to implement backoff correctly. Include Retry-After on 429 responses. Rate limits that exist but aren't documented cause production incidents when clients hit them unexpectedly.

Frequently Asked Questions

Should API endpoints use plural or singular nouns?+
Plural nouns are the dominant convention and the right default: /users not /user, /orders not /order. The reasoning: these endpoints represent collections. /users returns a list; /users/123 returns one item from the collection. Singular feels natural for single-item endpoints but creates inconsistency. Pick plural and stay consistent throughout — inconsistency is the real problem, not the choice itself.
How should I version a REST API?+
URL versioning (/v1/users, /v2/users) is the most common and most visible approach — easy to test in a browser, explicit in logs. Header versioning (Accept: application/vnd.myapi.v1+json) is preferred by API purists because URLs should identify resources not versions, but harder to test and debug. Query parameter versioning (?version=1) is common in public APIs. URL versioning wins for pragmatic reasons. Start versioning from v1 on day one, even for internal APIs — adding it later requires coordination across all clients.
What's the right HTTP status code for validation errors?+
422 Unprocessable Entity is the correct code for validation errors — the request is syntactically valid JSON but semantically invalid (missing required field, wrong value, etc.). 400 Bad Request should be for malformed requests (invalid JSON, wrong Content-Type). The distinction matters for clients: 400 means 'fix your request format', 422 means 'fix your data'. Include field-level error detail in the response body: {errors: [{field: 'email', message: 'Invalid email format'}]}.
How should pagination work in a REST API?+
Cursor-based pagination is preferred for large datasets: return a nextCursor token with each response, clients pass it as a parameter to get the next page. It handles real-time data correctly (page 2 doesn't skip items if new items were added after page 1). Offset pagination (?page=2&limit=20) is simpler but has the 'moving floor' problem with frequently updated datasets. For small, stable datasets, offset is fine. For feeds, search results, or anything with frequent updates, cursor-based is worth the extra implementation effort.

🔧 Free Tools Used in This Guide

FT

FreeToolKit Team

FreeToolKit Team

We build free browser-based tools and write practical guides without the fluff.

Tags:

apirestdeveloperbackend