149 lines
3.6 KiB
Markdown
149 lines
3.6 KiB
Markdown
---
|
|
name: api-design
|
|
description: REST API design patterns — resource naming, pagination (cursor/offset), error response format, versioning, idempotency, HATEOAS. Use when designing new APIs, reviewing existing ones, or standardizing API conventions.
|
|
---
|
|
|
|
# API Design Patterns
|
|
|
|
Based on ECC api-design skill.
|
|
|
|
## RESTful Resource Naming
|
|
|
|
### Good
|
|
```
|
|
GET /users # List users
|
|
POST /users # Create user
|
|
GET /users/:id # Get user
|
|
PUT /users/:id # Replace user
|
|
PATCH /users/:id # Update user (partial)
|
|
DELETE /users/:id # Delete user
|
|
|
|
GET /users/:id/posts # User's posts
|
|
POST /users/:id/posts # Create post for user
|
|
GET /users/:id/posts/:postId # Specific post by user
|
|
```
|
|
|
|
### Bad
|
|
```
|
|
GET /getUser # Action-based (wrong)
|
|
POST /createUser # Verb-based (wrong)
|
|
GET /posts?userId=123 # Flat when nested makes sense
|
|
```
|
|
|
|
### Rules
|
|
- **Nouns for resources**, verbs for HTTP methods
|
|
- **Plural nouns** for collections: `/users`, not `/user`
|
|
- **Nested resources** for parent-child: `/users/:id/posts`
|
|
- **Hyphens** for multi-word resource names: `/blog-posts`, not `/blogPosts`
|
|
- **Lowercase** only, no trailing slashes
|
|
|
|
## HTTP Status Codes
|
|
|
|
| Code | When to Use |
|
|
|------|------------|
|
|
| 200 | Successful GET, PUT, PATCH |
|
|
| 201 | Successful POST (created) — include Location header |
|
|
| 204 | Successful DELETE — no response body |
|
|
| 400 | Invalid request format, missing required fields |
|
|
| 401 | Authentication required or failed |
|
|
| 403 | Authenticated but not authorized |
|
|
| 404 | Resource not found |
|
|
| 409 | Conflict (duplicate, version mismatch) |
|
|
| 422 | Valid JSON but business rule violation |
|
|
| 429 | Rate limit exceeded |
|
|
| 500 | Unexpected server error — always log the real cause |
|
|
|
|
## Error Response Format
|
|
|
|
```json
|
|
{
|
|
"error": {
|
|
"code": "VALIDATION_ERROR",
|
|
"message": "Invalid request parameters",
|
|
"details": [
|
|
{
|
|
"field": "email",
|
|
"message": "Must be a valid email address"
|
|
}
|
|
],
|
|
"request_id": "req_abc123"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Error codes to use consistently
|
|
- `VALIDATION_ERROR` — input validation failed
|
|
- `NOT_FOUND` — resource doesn't exist
|
|
- `UNAUTHORIZED` — auth missing or expired
|
|
- `FORBIDDEN` — lacks permission
|
|
- `RATE_LIMITED` — too many requests
|
|
- `CONFLICT` — duplicate or version mismatch
|
|
- `INTERNAL_ERROR` — unexpected server failure
|
|
|
|
## Pagination
|
|
|
|
### Cursor-based (RECOMMENDED for large datasets)
|
|
```json
|
|
{
|
|
"data": [...],
|
|
"pagination": {
|
|
"next_cursor": "eyJpZCI6MTAwfQ==",
|
|
"has_more": true,
|
|
"limit": 20
|
|
}
|
|
}
|
|
```
|
|
|
|
### Offset-based (acceptable for small datasets)
|
|
```json
|
|
{
|
|
"data": [...],
|
|
"pagination": {
|
|
"total": 500,
|
|
"page": 2,
|
|
"per_page": 20,
|
|
"total_pages": 25
|
|
}
|
|
}
|
|
```
|
|
|
|
## API Versioning
|
|
|
|
### URL path versioning (simplest)
|
|
```
|
|
/api/v1/users
|
|
/api/v2/users
|
|
```
|
|
|
|
### Header versioning (cleaner)
|
|
```
|
|
Accept: application/vnd.api+json; version=1
|
|
```
|
|
|
|
## Idempotency
|
|
|
|
- **GET, PUT, DELETE** are naturally idempotent
|
|
- **POST** needs idempotency for safety:
|
|
- Accept `Idempotency-Key` header
|
|
- Store hash of request + result
|
|
- Return cached result if same key received again
|
|
|
|
## Rate Limiting
|
|
|
|
```
|
|
X-RateLimit-Limit: 1000
|
|
X-RateLimit-Remaining: 999
|
|
X-RateLimit-Reset: 1625097600
|
|
```
|
|
|
|
## Checklist
|
|
|
|
- [ ] Resources use plural nouns
|
|
- [ ] HTTP methods match CRUD operations
|
|
- [ ] Consistent error response format
|
|
- [ ] Pagination on all list endpoints
|
|
- [ ] Rate limiting on public endpoints
|
|
- [ ] Authentication on protected endpoints
|
|
- [ ] API documentation (OpenAPI/Swagger)
|
|
- [ ] Backward compatibility for version changes
|