What are best practices for designing a REST API?

3 minintermediatenodejsrestapi-designhttpstatus-codes

Quick Answer

Model resources as nouns with plural paths (/users, /users/:id), use HTTP methods for actions (GET/POST/PUT/PATCH/DELETE), return correct status codes, and keep endpoints stateless. Add versioning, pagination/filtering for collections, consistent error shapes, and validation at the boundary.

Detailed Answer

Answer:

Resources as nouns, methods as verbs:

GET    /users          # list
POST   /users          # create
GET    /users/:id      # read one
PUT    /users/:id      # replace
PATCH  /users/:id      # partial update
DELETE /users/:id      # delete
GET    /users/:id/orders   # nested/related resource

Avoid verbs in paths (/getUsers, /createUser) — the HTTP method conveys the action.

Meaningful status codes:

  • 200 OK, 201 Created, 204 No Content
  • 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422 Unprocessable Entity
  • 500 Internal Server Error, 503 Service Unavailable

Collections need pagination/filtering/sorting:

GET /users?page=2&limit=20&sort=-createdAt&role=admin

Never return unbounded lists — page them.

Other essentials:

  • Versioning/api/v1/... (or a header) so you can evolve without breaking clients.
  • Statelessness — each request carries its own auth (e.g., a bearer token); no server-side session affinity, which makes horizontal scaling trivial.
  • Consistent error shape — e.g., { "error": { "code": "...", "message": "..." } } everywhere.
  • Validation at the boundary (e.g., zod, joi) — reject bad input with 400/422 before it reaches business logic.
  • IdempotencyPUT/DELETE should be safe to retry; consider idempotency keys for POST.
  • Security — auth/authz, rate limiting, HTTPS, and don't leak internal details in errors.