Design REST APIs that developers love — resource naming, HTTP methods, status codes, versioning, and error handling conventions.
URLs should represent resources (nouns), not actions (verbs). Use plural nouns.
✅ Good
GET /users → list users
GET /users/123 → get user 123
POST /users → create user
PUT /users/123 → replace user 123
PATCH /users/123 → partially update user 123
DELETE /users/123 → delete user 123
❌ Bad
GET /getUsers
POST /createUser
GET /deleteUser?id=123
For nested resources:
GET /users/123/orders → orders belonging to user 123
GET /users/123/orders/456 → specific order
| Method | Purpose | Idempotent | Safe |
|---|---|---|---|
| GET | Read | Yes | Yes |
| POST | Create | No | No |
| PUT | Replace | Yes | No |
| PATCH | Partial update | No | No |
| DELETE | Delete | Yes | No |
Idempotent: calling it multiple times produces the same result. GET, PUT, DELETE are idempotent — POST is not.
Use the right status code — don't return 200 OK for errors.
200 OK → successful GET, PATCH
201 Created → successful POST
204 No Content → successful DELETE
400 Bad Request → invalid input
401 Unauthorized → not authenticated
403 Forbidden → authenticated but no permission
404 Not Found → resource doesn't exist
409 Conflict → duplicate, version mismatch
422 Unprocessable → validation failed
429 Too Many Requests → rate limited
500 Internal Server Error → bug on your end
// POST /users — request body
{
"name": "Trong Ngo",
"email": "trong@example.com",
"role": "admin"
}
// 201 Created — response
{
"id": "usr_abc123",
"name": "Trong Ngo",
"email": "trong@example.com",
"role": "admin",
"createdAt": "2025-06-01T10:00:00Z"
}
URL versioning (most common): /v1/users
Header versioning: Accept: application/vnd.api+json;version=1
Query param (least preferred): /users?version=1
Always version your public API from day one — it's painful to add later.
Return structured, actionable errors:
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Request validation failed",
"details": [
{ "field": "email", "message": "Must be a valid email address" },
{ "field": "name", "message": "Required" }
]
}
}