RESTful Best Practices: Conventions That Make APIs Predictable
Fifteen conventions that make REST APIs a joy to use — and the absence of any one is a smell.
Why conventions matter
A "RESTful" API is predictable. If a developer has used three of your endpoints, they can guess how the fourth works. That predictability compounds — each new endpoint takes less time to understand, test, and integrate with.
The fifteen conventions below aren't rules. They're defaults that work. Deviate when you have a reason; follow them when you don't.
1. Use plural nouns for collections
- ✓
GET /users,GET /users/123 - ✗
GET /user,GET /getUser/123
Plural nouns scale cleanly to both collection and single-resource URLs.
2. Nest resources only when the relationship is strong
- ✓
GET /users/123/orders(an order inherently belongs to a user) - ✗
GET /users/123/products/456(products exist independently)
Deep nesting (three levels or more) almost always hurts. Prefer flat URLs with query parameters.
3. Use HTTP methods, not verbs in URLs
- ✓
DELETE /users/123 - ✗
POST /users/123/delete,GET /deleteUser?id=123
4. Use standard status codes
Don't invent codes. If the request succeeded, return 200, 201, or 204. If the client messed up, 4xx. If you messed up, 5xx. See the status codes lesson.
5. Return consistent error envelopes
Pick one error shape and use it everywhere:
{
"success": false,
"error": "VALIDATION_ERROR",
"message": "Email is not valid",
"details": [{ "field": "email", "code": "invalid_format" }]
}
Inconsistent error shapes are the #1 thing that breaks automated tests against an API.
6. Version via URL prefix
- ✓
/api/v1/users - ✗ Custom header versioning, content-type versioning (too clever, too hard to test)
Start at v1 even if it's your first version. You'll need v2 eventually.
7. Use ISO 8601 for timestamps
- ✓
2026-05-01T14:30:00Z - ✗ Unix epochs (hard for humans), US-locale strings (ambiguous)
Always UTC. Let the client convert to the user's timezone.
8. Use UUIDs, not auto-increment IDs, where possible
Auto-increment exposes customer counts, creates guessability vulnerabilities, and makes database merges painful. UUIDs are 36 characters of don't-think-about-it.
9. Paginate every list endpoint
Every list endpoint. No exceptions. Even if you think "there'll only be a few." Covered in detail in query parameters and pagination.
10. Return the resource after writes
POST, PUT, PATCH should all return the full resource in the response. Saves the client a follow-up GET. The exception: DELETE, which returns 204 No Content.
11. Support idempotency keys on POST
A client-supplied Idempotency-Key header lets clients retry POSTs safely: if the server sees the same key, it returns the cached response instead of creating a duplicate. Stripe popularized this pattern and it's now widely adopted.
12. Rate-limit, and communicate it clearly
Return x-ratelimit-limit, x-ratelimit-remaining, and x-ratelimit-reset on every response. When a client hits the limit, return 429 with a Retry-After header.
13. Use CORS correctly
If browsers should call your API directly, send Access-Control-Allow-Origin with specific origins, not *. Don't enable CORS for endpoints that handle cookies or auth unless you fully understand CSRF implications.
14. Document with OpenAPI
OpenAPI (formerly Swagger) is the de facto standard for describing REST APIs. A machine-readable spec unlocks:
- Auto-generated client SDKs
- Auto-generated test suites (what ShiftLeft does)
- Interactive documentation (Swagger UI, ReDoc)
- Contract testing
No OpenAPI = you're manually writing docs, SDKs, and tests that all drift out of sync. In 2026 this is inexcusable.
15. Keep the response envelope predictable
Pick a shape and use it everywhere. Two common patterns:
Envelope-wrapped:
{ "success": true, "data": {...}, "meta": {...} }
Raw:
{ "id": "...", "name": "...", ... }
Either works. Mixed does not. Testers spend hours writing conditional assertions because some endpoints wrap in { data: ... } and others don't.
Bonus: deprecate gracefully
When you remove a field or endpoint:
- Announce the deprecation at least 90 days in advance.
- Send a
Deprecationheader with the date. - Keep the old behavior working through the deprecation window.
- Log usage so you can warn the last remaining clients before pulling it.
What's next
You've seen the conventions. Now dig into GraphQL — the modern alternative to REST that solves over-fetching — or jump to authentication.
Related lessons
REST is the default API style on the web. Here's what it actually means — stripped of jargon and with runnable examples.
CRUD is the heartbeat of REST. Create, Read, Update, Delete — walked through end to end.
PUT replaces. PATCH modifies. Here's the subtle but critical difference — and why it matters for testing.
Read more on the blog
REST API testing best practices in 2026 go far beyond basic status code checks — they encompass schema validation, authentication testing, negative and boundary testing, data-driven tests, and automated generation from OpenAPI specs. This guide covers every dimension of effective REST API testing with practical examples.
API schema validation drift detection is the automated process of comparing live API responses against the documented OpenAPI specification to identify undocumented changes in field types, required properties, response formats, and nested structures. When drift goes undetected, it silently breaks API consumers and causes production integration failures.