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.
Frequently asked questions
Which REST API guidelines make an API easier to test?+
Consistent error envelopes and a predictable response envelope matter most, because inconsistent shapes are the top thing that breaks automated tests. Standard status codes, URL-prefix versioning, and pagination on every list endpoint also keep tests simple and reusable.
How does OpenAPI support REST API testing best practices?+
OpenAPI is the de facto standard for describing REST APIs in a machine-readable spec. It enables auto-generated test suites, client SDKs, interactive documentation, and contract testing. Without it, docs, SDKs, and tests are written by hand and drift out of sync.
Why should a REST API be versioned in the URL?+
A URL prefix such as /api/v1/users is simple and easy to test, while custom header or content-type versioning is harder to test. Start at v1 even for a first release, because you will eventually need a v2.
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
Twelve REST API testing best practices for enterprise teams in 2026 — schema validation against OpenAPI, authentication across enterprise IdPs, negative and boundary testing, data-driven coverage, audit-ready evidence, and CI/CD automation. Worked examples for each pattern.
What API schema validation is, how to validate requests and responses against an OpenAPI contract in tests, in CI and at the API gateway, the tools that do it (Ajv, Schemathesis, Prism, REST Assured, Postman), and how to catch schema drift.