DEV Community

DatanestDigital
DatanestDigital

Posted on

REST API Design: 12 Rules for Endpoints Developers Won't Hate (2026)

A good REST API feels obvious. You guess the URL and you're right; you read one error and you know exactly what to fix. A bad one makes you keep the docs open in a second monitor and reverse-engineer behavior from 200-responses that secretly contain failures.

The difference is rarely the framework. It's a handful of conventions applied consistently. Here are twelve rules that, followed together, produce an API integrators don't complain about.

1. Name resources with plural nouns, not verbs

The HTTP method is the verb. The path is the thing.

GET    /users           # list
POST   /users           # create
GET    /users/42        # read
PATCH  /users/42        # partial update
DELETE /users/42        # delete
Enter fullscreen mode Exit fullscreen mode

Not /getUser, /createUser, /user/delete. The method already says what you're doing.

2. Nest only to show ownership — then stop

GET /users/42/orders is fine: orders belong to a user. But don't go three levels deep. Past one level of nesting, switch to query parameters: GET /orders?user=42&status=open.

3. Use HTTP status codes honestly

Return the code that's true, not 200 with {"success": false}.

  • 200 OK, 201 Created, 204 No Content
  • 400 bad request, 401 unauthenticated, 403 unauthorized, 404 not found, 409 conflict, 422 validation failed
  • 429 rate limited, 500 server error

A client should be able to branch on the status line alone.

4. Return a consistent error shape

Every error, everywhere, in the same structure. Machine-readable code, human message, and field-level detail when relevant.

{
  "error": {
    "code": "validation_failed",
    "message": "Email is not valid.",
    "details": [{ "field": "email", "issue": "format" }]
  }
}
Enter fullscreen mode Exit fullscreen mode

Pick this shape once and never deviate. Clients build error handling around it.

5. PATCH for partial, PUT for full replacement

PATCH /users/42 with { "email": "..." } changes one field. PUT means "replace the whole resource with this representation." Don't make PUT behave like PATCH; you'll surprise everyone.

6. Make writes idempotent where you can

PUT and DELETE should be safe to retry. For POST (create), support an Idempotency-Key header so a client that retries after a network blip doesn't create two orders.

7. Paginate from day one

A collection that returns "all rows" works in dev and falls over in production. Decide on a strategy early. Cursor pagination scales better than offset for large, changing datasets.

GET /users?limit=50&cursor=eyJpZCI6MTAwfQ
Enter fullscreen mode Exit fullscreen mode
{ "data": [ ... ], "next_cursor": "eyJpZCI6MTUwfQ", "has_more": true }
Enter fullscreen mode Exit fullscreen mode

8. Filter, sort, and select with query params

Keep the path about identity; put the query in the query string.

GET /orders?status=open&sort=-created_at&fields=id,total
Enter fullscreen mode Exit fullscreen mode

-created_at for descending is a tiny convention that saves a lot of guessing.

9. Version at the edge, before you need to

Put a version in the URL (/v1/...) or a header from the very first release. The day you must make a breaking change, /v2 lets existing clients keep working instead of breaking in production.

10. Be consistent about field casing and dates

Pick snake_case or camelCase and apply it to every field in every response. Use ISO 8601 UTC for timestamps (2026-06-20T11:00:00Z). Mixed casing and ambiguous local dates are a thousand tiny paper cuts.

11. Don't leak your database

Your API is a contract, not a SQL dump. Don't expose internal auto-increment IDs if they reveal volume, don't return columns clients shouldn't see, and don't let the response shape change because you refactored a table. The representation is yours to design.

12. Document with real examples, and keep them true

The best docs are copy-pasteable requests and their exact responses. Generate an OpenAPI spec from the code so the docs can't drift from behavior — a lying example is worse than none.

The through-line

Every rule above is really one rule: be predictable. When naming, status codes, errors, pagination, and dates are uniform across every endpoint, a developer who learns one part of your API has effectively learned all of it.

If you want these conventions as a ready-made starting point — endpoint templates, the standard error envelope, pagination helpers, and an OpenAPI skeleton — the REST API Design Guide packages them so a new service is consistent on day one instead of after the third refactor.

Bottom line

APIs are read far more often than they're written. Spend the design effort up front on consistency, and every future integrator — including future you — inherits an interface they can guess their way through.

Top comments (0)