API Design Guidelines
RESTful Design Principles​
1. Resource Naming​
# Good Examples
/api/v1/users # List users
/api/v1/users/{id} # Single user
/api/v1/users/{id}/posts # User's posts
/api/v1/teams/{id}/members # Team members
# Bad Examples
/api/v1/getUsers # Uses verb
/api/v1/user_profiles # Inconsistent naming
/api/v1/teamMembers # Not hierarchical
2. HTTP Methods Usage​
| Method | Usage | Example | Success Code |
|---|---|---|---|
| GET | Read/Retrieve | GET /api/users | 200 OK |
| POST | Create | POST /api/users | 201 Created |
| PUT | Update/Replace | PUT /api/users/123 | 200 OK |
| PATCH | Partial Update | PATCH /api/users/123 | 200 OK |
| DELETE | Delete | DELETE /api/users/123 | 204 No Content |
Request/Response Format​
1. Request Format​
// POST /api/v1/users
{
"name": "John Doe",
"email": "[email protected]",
"role": "user"
}
2. Success Response​
// 200 OK
{
"data": {
"id": "123",
"name": "John Doe",
"email": "[email protected]",
"role": "user",
"createdAt": "2025-02-04T00:00:00Z"
},
"meta": {
"timestamp": "2025-02-04T00:00:00Z"
}
}
3. Error Response​
// 400 Bad Request
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"details": {
"email": "Must be a valid email address"
}
},
"meta": {
"timestamp": "2025-02-04T00:00:00Z"
}
}
4. Collection Response​
// GET /api/v1/users
{
"data": [
{
"id": "123",
"name": "John Doe",
"email": "[email protected]"
}
],
"meta": {
"pagination": {
"total": 100,
"page": 1,
"perPage": 10,
"totalPages": 10
},
"timestamp": "2025-02-04T00:00:00Z"
}
}
Status Codes​
Success Codes​
- 200: OK (Success)
- 201: Created (Resource created)
- 204: No Content (Success, no response body)
Client Error Codes​
- 400: Bad Request (Invalid input)
- 401: Unauthorized (Not authenticated)
- 403: Forbidden (Not authorized)
- 404: Not Found (Resource not found)
- 409: Conflict (Resource conflict)
- 422: Unprocessable Entity (Validation failed)
Server Error Codes​
- 500: Internal Server Error
- 502: Bad Gateway
- 503: Service Unavailable
- 504: Gateway Timeout
Authentication & Authorization​
1. JWT Authentication​
interface JWTPayload {
sub: string; // Subject (user ID)
iat: number; // Issued at
exp: number; // Expiration time
scope: string[]; // Permissions
}
2. OAuth2 Flow​
- Client Registration
- Authorization Request
- User Consent
- Token Exchange
- Resource Access
3. API Keys​
// Request Header
Authorization: Bearer <api_key>
// Query Parameter (less secure)
/api/v1/users?api_key=<api_key>
Versioning​
1. URL Versioning​
/api/v1/users
/api/v2/users
2. Header Versioning​
Accept: application/vnd.company.api+json;version=1
3. Query Parameter​
/api/users?version=1
Rate Limiting​
1. Headers​
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1612345678
2. Response (429 Too Many Requests)​
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"details": {
"retryAfter": 3600
}
}
}
Documentation​
1. OpenAPI Specification​
openapi: 3.0.0
info:
title: API Documentation
version: 1.0.0
paths:
/users:
get:
summary: List users
parameters:
- name: page
in: query
schema:
type: integer
responses:
'200':
description: Success
2. API Documentation Example​
/**
* Create a new user
* @route POST /api/v1/users
* @param {Object} body.required - User data
* @param {string} body.name.required - User's full name
* @param {string} body.email.required - User's email
* @returns {Object} 201 - Created user object
* @returns {Error} 400 - Validation error
*/
Security​
1. Input Validation​
interface CreateUserRequest {
name: string;
email: string;
role: 'admin' | 'user';
}
function validateCreateUser(data: unknown): CreateUserRequest {
// Validation logic
}
2. Security Headers​
app.use(helmet()); // Adds security headers
// Custom headers
res.setHeader('Content-Security-Policy', "default-src 'self'");
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
3. CORS Configuration​
app.use(cors({
origin: ['https://example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));