Master REST API design principles to build intuitive, scalable, and maintainable APIs. Use when designing new APIs, reviewing API specifications, or establishing API design standards.
Master REST API design principles to build intuitive, scalable, and maintainable APIs. This skill focuses on design theory - for implementation patterns, see abp-api-implementation or abp-service-patterns.
For Implementation: Use
abp-service-patternsfor AppService code,api-response-patternsfor response wrappers,fluentvalidation-patternsfor validation.
APIs expose resources (nouns), not actions (verbs).
| Concept | Good | Bad |
|---|---|---|
| Resource naming | /patients, /appointments |
/getPatients, /createAppointment |
| Actions via HTTP methods | POST /patients |
POST /createPatient |
| Plural for collections | /patients |
/patient |
| Consistent casing | kebab-case or camelCase |
Mixed styles |
Resource Hierarchy:
/api/v1/patients # Collection
/api/v1/patients/{id} # Single resource
/api/v1/patients/{id}/appointments # Nested collection
/api/v1/appointments/{id} # Direct access to nested resource
Avoid Deep Nesting (max 2 levels):
# Good - Shallow
GET /api/v1/patients/{id}/appointments
GET /api/v1/appointments/{id}
# Bad - Too deep
GET /api/v1/clinics/{id}/doctors/{id}/patients/{id}/appointments/{id}
| Method | Purpose | Idempotent | Safe | Request Body |
|---|---|---|---|---|
GET |
Retrieve resource(s) | Yes | Yes | No |
POST |
Create resource | No | No | Yes |
PUT |
Replace entire resource | Yes | No | Yes |
PATCH |
Partial update | Yes* | No | Yes |
DELETE |
Remove resource | Yes | No | No |
Idempotent: Multiple identical requests produce same result. Safe: Does not modify server state.
Success (2xx):
| Code | Meaning | Use When |
|---|---|---|
200 OK |
Success | GET, PUT, PATCH succeeded |
201 Created |
Resource created | POST succeeded |
204 No Content |
Success, no body | DELETE succeeded |
Client Errors (4xx):
| Code | Meaning | Use When |
|---|---|---|
400 Bad Request |
Malformed request | Invalid JSON, missing required headers |
401 Unauthorized |
Not authenticated | Missing or invalid token |
403 Forbidden |
Not authorized | Valid token, insufficient permissions |
404 Not Found |
Resource doesn't exist | ID not found |
409 Conflict |
State conflict | Duplicate email, version mismatch |
422 Unprocessable Entity |
Validation failed | Business rule violations |
429 Too Many Requests |
Rate limited | Exceeded request quota |
Server Errors (5xx):
| Code | Meaning | Use When |
|---|---|---|
500 Internal Server Error |
Unexpected error | Unhandled exception |
503 Service Unavailable |
Temporarily down | Maintenance, overload |
Always paginate collections - Never return unbounded lists.
Offset-Based (simple, good for small datasets):
GET /api/v1/patients?page=2&pageSize=20
Response:
{
"items": [...],
"totalCount": 150,
"pageNumber": 2,
"pageSize": 20,
"totalPages": 8
}
Cursor-Based (efficient for large datasets, real-time data):
GET /api/v1/patients?cursor=eyJpZCI6MTIzfQ&limit=20
Response:
{
"items": [...],
"nextCursor": "eyJpZCI6MTQzfQ",
"hasMore": true
}
| Approach | Pros | Cons | Best For |
|---|---|---|---|
| Offset | Simple, supports jumping to page | Slow on large datasets, inconsistent with real-time data | Admin panels, reports |
| Cursor | Fast, consistent | Can't jump to arbitrary page | Infinite scroll, feeds |
Query Parameters for Filtering:
GET /api/v1/patients?status=active
GET /api/v1/patients?status=active&createdAfter=2025-01-01
GET /api/v1/patients?doctorId=abc-123
Sorting:
GET /api/v1/patients?sorting=name
GET /api/v1/patients?sorting=createdAt desc
GET /api/v1/patients?sorting=lastName,firstName
Searching:
GET /api/v1/patients?filter=john
GET /api/v1/patients?search=john doe
Design Decisions:
WhereIf pattern - only apply filter if parameter providedConsistent Structure:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "One or more validation errors occurred.",
"details": [
{
"field": "email",
"message": "Invalid email format."
},
{
"field": "dateOfBirth",
"message": "Date of birth cannot be in the future."
}
],
"traceId": "00-abc123-def456-00"
}
}
Error Codes (for client handling):
| Code | HTTP Status | Meaning |
|---|---|---|
VALIDATION_ERROR |
422 | Input validation failed |
NOT_FOUND |
404 | Resource doesn't exist |
UNAUTHORIZED |
401 | Authentication required |
FORBIDDEN |
403 | Permission denied |
CONFLICT |
409 | State conflict |
RATE_LIMITED |
429 | Too many requests |
URL Versioning (Recommended for ABP):
/api/v1/patients
/api/v2/patients
| Strategy | Example | Pros | Cons |
|---|---|---|---|
| URL Path | /api/v1/ |
Clear, easy routing | Multiple URLs |
| Header | Api-Version: 1 |
Clean URLs | Hidden, harder to test |
| Query Param | ?version=1 |
Easy testing | Can be forgotten |
Versioning Policy:
Embedding vs Linking:
// Embedded (fewer requests, larger payload)
{
"id": "patient-123",
"name": "John Doe",
"doctor": {
"id": "doctor-456",
"name": "Dr. Smith"
}
}
// Linked (smaller payload, more requests)
{
"id": "patient-123",
"name": "John Doe",
"doctorId": "doctor-456"
}
// Hybrid (with expand parameter)
GET /api/v1/patients/123?expand=doctor,appointments
Decision Criteria:
| Use Embedding | Use Linking |
|---|---|
| Related data always needed | Related data rarely needed |
| Few relationships | Many relationships |
| Related data is small | Related data is large |
| Anti-Pattern | Problem | Solution |
|---|---|---|
| Verb endpoints | POST /createPatient |
POST /patients |
| Ignoring HTTP methods | Using POST for everything | Use appropriate method |
| No pagination | Returning 10,000 items | Always paginate |
| Inconsistent errors | Different formats per endpoint | Standardize error structure |
| Exposing internals | Database columns in API | Design API contract separately |
| No versioning | Breaking changes break clients | Version from day one |
| Deep nesting | /a/{id}/b/{id}/c/{id}/d |
Flatten, max 2 levels |
| Need | Skill |
|---|---|
| AppService implementation | abp-service-patterns |
| Response wrappers | api-response-patterns |
| Input validation | fluentvalidation-patterns |
| Query optimization | linq-optimization-patterns |
| Technical design docs | technical-design-patterns |
references/rest-best-practices.md - Detailed REST patternsassets/api-design-checklist.md - Pre-implementation checklist