API Design Best Practices: RESTful Guide 2026
RESTful API Design Principles That Stand the Test of Time
REST API design has accumulated a set of battle-tested conventions over two decades of production use. The fundamentals haven't changed: use nouns for resource URLs not verbs, use HTTP methods semantically (GET for reads, POST for creates, PUT/PATCH for updates, DELETE for deletion), return appropriate HTTP status codes, and design for the consumer. The APIs that are a pleasure to work with in 2026 follow these fundamentals rigorously and add modern practices around versioning, authentication, documentation, and error responses.
URL Structure and Resource Naming
Resource URLs should be nouns in the plural form: /users not /user, /products not /product, /templates not /template. Nested resources use the parent path: /users/{id}/posts for a specific user's posts. Query parameters handle filtering, sorting, and pagination: /products?category=dashboard&sort=price&order=asc&page=2&limit=20. Avoid query parameters for resources that should have permanent URLs — /products/featured is preferable to /products?featured=true when the featured collection is a stable, linkable resource. Keep URLs lowercase, use hyphens not underscores, and avoid file extensions in URLs.
HTTP Status Codes: Use Them Correctly
The most common mistake in REST API design is returning 200 OK for error responses. Use 200 for successful reads, 201 for successful creates (with Location header pointing to the new resource), 204 for successful deletes with no body, 400 for client errors with validation details in the body, 401 for unauthenticated (no valid credentials), 403 for unauthorized (credentials valid but insufficient permissions), 404 for resources that don't exist, 422 for validation errors with field-level details, 429 for rate limit exceeded with Retry-After header, and 500 for server errors that the client cannot resolve.
Authentication: JWT vs API Keys vs OAuth
Choose the authentication mechanism based on the API consumer. Public APIs used by third-party developers: API keys for simple cases, OAuth 2.0 with PKCE for user-scoped access. Internal APIs consumed by your own frontend: JWT with short expiry (15 minutes) and refresh tokens stored in httpOnly cookies. Machine-to-machine APIs: OAuth 2.0 client credentials flow or mTLS. API keys should be long (32+ characters), randomly generated, hashed before storage, and scoped to specific permissions. JWTs should be signed with RS256 (asymmetric) for APIs with multiple verification endpoints, HS256 for single-service tokens.
Error Response Format
Consistent error responses are critical for API usability. Define a standard error object and use it everywhere: include an error code (machine-readable string like RESOURCE_NOT_FOUND), a human-readable message, optional details array for validation errors with field-level information, and a request ID for tracing. Never expose stack traces, internal error messages, or database errors in production API responses. The error code should be stable across API versions so clients can write conditional logic against it.
Pagination, Filtering, and Sorting
Cursor-based pagination is more reliable than offset pagination for large datasets — it doesn't miss items when data is inserted between page loads and performs better on large tables. Return a cursor pointing to the last item in the response, and clients send cursor=abc123 to get the next page. For filtering, use the Django-style field__lookup pattern or GraphQL-style filter objects for complex queries. Always return total count and next/previous links in paginated responses. ProofMatcher's API templates include pre-built pagination and filtering patterns for Django REST Framework — download free at proofmatcher.com.
Versioning Without Breaking Clients
Every public API eventually needs changes that would break existing clients. Plan for it from the first release. The most common and easiest to understand approach is a version in the URL, such as /v1/orders. Header-based versioning keeps URLs clean but is harder to test in a browser and to see in logs. Whichever you choose, only introduce a new version for breaking changes. Adding a new optional field or a new endpoint is backwards compatible and does not need one, while removing or renaming fields, changing types, or changing behaviour does.
When you retire an old version, announce the date well in advance, return a Deprecation or Sunset header on responses from the old version, and keep documentation for both versions until the old one is shut down.
Idempotency for Safe Retries
Networks fail, and clients retry. GET, PUT, and DELETE are idempotent by definition: repeating them has the same effect as sending them once. POST is not, so a retried "create payment" request can charge a customer twice. Solve this with idempotency keys. The client sends a unique Idempotency-Key header with each operation, the server stores the key with the result, and if the same key arrives again it returns the stored result instead of repeating the action. Payment providers such as Stripe use exactly this pattern.
Rate Limiting and Clear Limits
Protect your API and its users with rate limits per API key or per user. When a client exceeds the limit, return 429 Too Many Requests with a Retry-After header telling it when to try again. Also return the current limit and remaining allowance in response headers so well-behaved clients can slow down before they hit the wall. Document the limits clearly, and consider higher limits for authenticated or paying clients.
Caching with ETags
For resources that change rarely, HTTP caching saves bandwidth and server work. Return an ETag header that identifies the current version of a resource. The client sends it back in an If-None-Match header on the next request, and if nothing has changed the server responds with 304 Not Modified and no body. Add Cache-Control headers to say how long responses can be reused, and never cache responses that contain private user data in shared caches.
Consistency Matters More Than Any Single Rule
Developers forgive an unusual convention, but not an inconsistent one. Pick one naming style for fields, such as camelCase or snake_case, and use it everywhere. Use the same date format across the API, preferably ISO 8601 in UTC such as 2026-09-27T10:30:00Z. Use the same pagination style, the same error format, and the same approach to IDs on every endpoint. A short internal style guide, checked during code review, keeps a growing API coherent as more people work on it.
Documentation and Security Basics
Describe your API with an OpenAPI specification. It powers interactive documentation, lets clients generate typed SDKs, and can be used to validate requests automatically. Keep examples realistic and include error responses, not only the happy path.
On the security side, serve every endpoint over HTTPS, validate and limit the size of all input, and never trust IDs sent by the client without checking that the authenticated user is allowed to access that resource. That last mistake, known as broken object level authorisation, is consistently one of the most common API vulnerabilities. Configure CORS to allow only the origins that need access, avoid exposing internal error details in responses, and log authentication failures so you can spot abuse early.
Designing Webhooks
Many APIs also need to notify clients when something happens, such as a payment succeeding or an order shipping. Webhooks do this by sending an HTTP POST to a URL the client registers. Design them as carefully as the rest of the API. Sign every webhook payload with a shared secret and include a timestamp, so receivers can verify that it came from you and reject replayed requests. Expect delivery failures and retry with exponential backoff for a reasonable period, and include a unique event ID so receivers can ignore duplicates. Keep payloads small and include the resource ID, so the receiver can fetch the latest state from the API rather than trusting an event that may arrive out of order. Finally, give developers a dashboard or endpoint to see recent deliveries and resend failed ones, which saves hours of support time.