Stage 3 · Build
HTTP, HTTP/2 & gRPC
REST API Design
Resources, verbs, status codes, pagination, idempotency, and versioning.
Resource Naming Conventions
REST APIs model the world as resources. Resources are nouns, not verbs. The URL identifies the resource, and the HTTP method identifies the action. Plural nouns represent collections; singular paths represent specific items.
GET /users # List users
POST /users # Create a user
GET /users/123 # Get user 123
PUT /users/123 # Replace user 123
PATCH /users/123 # Update user 123
DELETE /users/123 # Delete user 123
# Nested resources
GET /users/123/orders # Orders for user 123
GET /orders/456/items # Items in order 456
# Avoid:
GET /getUser # Verb in URL
GET /user/list # Action in URL
POST /deleteUser/123 # Wrong method + verbGood resource naming is consistent and predictable. If you use /users, use /orders, not /getOrders. If you nest resources, keep it to one level deep — /users/123/orders is fine, /users/123/orders/456/items/789 is not.
Using HTTP Verbs Correctly
| Action | Method | Idempotent | Request Body | Response |
|---|---|---|---|---|
| Create | POST | No | Resource data | 201 + Location header |
| Read one | GET | Yes | None | 200 + resource |
| Read all | GET | Yes | None | 200 + array |
| Replace | PUT | Yes | Full resource | 200 or 204 |
| Update | PATCH | No | Partial changes | 200 or 204 |
| Delete | DELETE | Yes | None | 204 No Content |
PUT replaces the entire resource. If you send PUT /users/123 with only the name field, all other fields are overwritten with defaults. PATCH updates only the fields you send. Use PATCH for partial updates.
Pagination Patterns
# Offset-based (traditional)
GET /users?offset=0&limit=20
GET /users?offset=20&limit=20
Response: {
"data": [...],
"total": 150,
"offset": 0,
"limit": 20
}
# Cursor-based (recommended)
GET /users?cursor=abc123&limit=20
Response: {
"data": [...],
"next_cursor": "def456",
"has_more": true
}
# Keyset pagination
GET /users?created_after=2024-01-01T00:00:00Z&limit=20Offset-based pagination breaks with real-time data (inserts/deletes shift the window). Cursor-based pagination is stable — the cursor points to a specific position in the dataset. Use cursor-based for infinite scroll and large datasets.
Filtering and Sorting
# Filtering
GET /users?status=active
GET /users?role=admin&status=active
GET /users?created_after=2024-01-01
# Sorting
GET /users?sort=-created_at # Descending (minus prefix)
GET /users?sort=created_at # Ascending
GET /users?sort=-created_at,name # Multiple sort fields
# Field selection
GET /users?fields=id,name,email
# Search
GET /users?q=john
GET /products?search=wireless+keyboardKeep filtering simple with query parameters. Use a consistent convention for sort order — minus prefix for descending is common. Field selection reduces payload size for mobile clients.
API Versioning
| Approach | Example | Pros | Cons |
|---|---|---|---|
| URL path | /v1/users | Explicit, easy to route | URL proliferation |
| Header | Accept: application/vnd.api.v1+json | Clean URLs | Harder to test |
| Query param | /users?version=1 | Easy to add | Looks hacky |
# URL path versioning (most common)
GET /v1/users
GET /v2/users
# Header versioning
GET /users
Accept: application/vnd.myapi.v2+json
# Content negotiation
GET /users
Accept: application/json; version=2URL path versioning is the most common approach. It is explicit, easy to route at the load balancer, and simple to test. When breaking changes are needed, create a new version and deprecate the old one on a defined timeline.
Additive changes (new fields, new endpoints) do not require a new version. Only bump the version for breaking changes: removing fields, changing types, or altering behavior. Design APIs to be forward-compatible.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.