Skip to content

API Design Principles

Good

GET /users
GET /users/1
POST /users
PUT /users/1
DELETE /users/1

Bad

GET /getUser
POST /createUser
DELETE /deleteUser

Resources should be nouns rather than verbs.


Method Purpose Example
GET Read Get product list
POST Create Create a new product
PUT Replace Update a product
PATCH Partial Update Update product price
DELETE Delete Delete a product

Servers should not store client session state.

Every request must contain everything required for processing.


/api/v1/users
/api/v2/users

Allows backward compatibility.

Strategy Example
URI Versioning /v1/products
Query Parameter /products?version=1
Header Versioning X-API-VERSION: 1
Media Type Versioning application/vnd.company.v1+json

URI versioning in practice, as separate controllers:

@RestController
@RequestMapping("/v1/products")
public class ProductControllerV1 {
}
@RestController
@RequestMapping("/v2/products")
public class ProductControllerV2 {
}

Repeated requests should produce the same result.

Example

PUT /users/1

Calling it multiple times produces the same state.


GET /users?page=1&size=20

Benefits

  • Better performance
  • Smaller responses

GET /users?status=ACTIVE
GET /users?department=IT

Code Meaning
200 Success
201 Created
204 No Content
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
409 Conflict
500 Internal Server Error

{
"timestamp": "2026-06-24T10:00:00",
"status": 400,
"message": "Invalid Request"
}

Consistent error responses simplify client-side error handling.


  • Name resources as nouns (/users/1), not verbs (/getUser) — let the HTTP method express the action.
  • PUT is idempotent by design (repeated calls converge to the same state); POST typically is not.
  • Version APIs (/api/v1/...) up front so breaking changes don’t require coordinated client/server deploys.
  • Keep responses consistent: standard status codes plus a uniform error body shape make client-side error handling predictable.