api-design-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAPI Design Patterns
API设计模式
RESTful API design principles, error handling, pagination, versioning, and security best practices. Guidelines for building consistent, developer-friendly APIs.
RESTful API设计原则、错误处理、分页、版本控制及安全最佳实践。旨在指导构建一致、对开发者友好的API。
When to Apply
适用场景
Reference these guidelines when:
- Designing new API endpoints
- Reviewing existing API structure
- Implementing error handling
- Setting up pagination/filtering
- Planning API versioning
在以下场景中可参考本指南:
- 设计新的API端点
- 评审现有API结构
- 实现错误处理逻辑
- 配置分页/过滤功能
- 规划API版本控制
Rule Categories by Priority
按优先级划分的规则类别
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Resource Design | CRITICAL | |
| 2 | Error Handling | CRITICAL | |
| 3 | Security | CRITICAL | |
| 4 | Pagination & Filtering | HIGH | |
| 5 | Versioning | HIGH | |
| 6 | Response Format | MEDIUM | |
| 7 | Documentation | MEDIUM | |
| 优先级 | 类别 | 影响程度 | 前缀 |
|---|---|---|---|
| 1 | 资源设计 | 关键 | |
| 2 | 错误处理 | 关键 | |
| 3 | 安全 | 关键 | |
| 4 | 分页与过滤 | 高 | |
| 5 | 版本控制 | 高 | |
| 6 | 响应格式 | 中 | |
| 7 | 文档 | 中 | |
Quick Reference
快速参考
1. Resource Design (CRITICAL)
1. 资源设计(关键)
- - Use nouns for endpoints
rest-nouns-not-verbs - - Use plural resource names
rest-plural-resources - - Correct HTTP method usage
rest-http-methods - - Proper resource nesting
rest-nested-resources - - Appropriate status codes
rest-status-codes - - Idempotent operations
rest-idempotency - - Hypermedia links
rest-hateoas
- - 端点使用名词
rest-nouns-not-verbs - - 资源名称使用复数形式
rest-plural-resources - - 正确使用HTTP方法
rest-http-methods - - 合理的资源嵌套
rest-nested-resources - - 使用恰当的状态码
rest-status-codes - - 幂等操作
rest-idempotency - - 超媒体链接
rest-hateoas
2. Error Handling (CRITICAL)
2. 错误处理(关键)
- - Consistent error structure
error-consistent-format - - Helpful error messages
error-meaningful-messages - - Field-level validation errors
error-validation-details - - Machine-readable error codes
error-codes - - Never expose in production
error-stack-traces
- - 统一的错误结构
error-consistent-format - - 有意义的错误提示
error-meaningful-messages - - 字段级验证错误
error-validation-details - - 机器可读的错误码
error-codes - - 生产环境绝不暴露堆栈跟踪
error-stack-traces
3. Security (CRITICAL)
3. 安全(关键)
- - Proper auth implementation
sec-authentication - - Resource-level permissions
sec-authorization - - Prevent abuse
sec-rate-limiting - - Validate all input
sec-input-validation - - CORS configuration
sec-cors - - Protect sensitive data
sec-sensitive-data
- - 正确实现认证
sec-authentication - - 资源级权限控制
sec-authorization - - 防止滥用
sec-rate-limiting - - 验证所有输入
sec-input-validation - - CORS配置
sec-cors - - 保护敏感数据
sec-sensitive-data
4. Pagination & Filtering (HIGH)
4. 分页与过滤(高)
- - Cursor pagination for large datasets
page-cursor-based - - Offset pagination for simple cases
page-offset-based - - Consistent parameter names
page-consistent-params - - Include pagination metadata
page-metadata - - Filter via query parameters
filter-query-params - - Flexible sorting options
sort-flexible
- - 大数据集使用游标分页
page-cursor-based - - 简单场景使用偏移分页
page-offset-based - - 统一的参数命名
page-consistent-params - - 包含分页元数据
page-metadata - - 通过查询参数实现过滤
filter-query-params - - 灵活的排序选项
sort-flexible
5. Versioning (HIGH)
5. 版本控制(高)
- - Version in URL path
ver-url-path - - Version in headers
ver-header-based - - Maintain compatibility
ver-backward-compatible - - Deprecation strategy
ver-deprecation
- - URL路径中包含版本
ver-url-path - - 请求头中包含版本
ver-header-based - - 保持向后兼容
ver-backward-compatible - - 弃用策略
ver-deprecation
6. Response Format (MEDIUM)
6. 响应格式(中)
- - Consistent response envelope
resp-consistent-structure - - JSON naming conventions
resp-json-conventions - - Field selection
resp-partial-responses - - Response compression
resp-compression
- - 统一的响应封装
resp-consistent-structure - - JSON命名规范
resp-json-conventions - - 字段选择
resp-partial-responses - - 响应压缩
resp-compression
7. Documentation (MEDIUM)
7. 文档(中)
- - OpenAPI/Swagger spec
doc-openapi - - Request/response examples
doc-examples - - API changelog
doc-changelog
- - OpenAPI/Swagger规范
doc-openapi - - 请求/响应示例
doc-examples - - API变更日志
doc-changelog
Essential Guidelines
核心指南
Resource Naming
资源命名
undefinedundefined❌ Verbs in URLs - RPC style
❌ URL中使用动词 - RPC风格
GET /getUsers
POST /createUser
PUT /updateUser/123
DELETE /deleteUser/123
GET /getUsers
POST /createUser
PUT /updateUser/123
DELETE /deleteUser/123
✅ Nouns with HTTP methods - REST style
✅ 结合HTTP方法使用名词 - REST风格
GET /users # List users
POST /users # Create user
GET /users/123 # Get user
PUT /users/123 # Update user (full)
PATCH /users/123 # Update user (partial)
DELETE /users/123 # Delete user
undefinedGET /users # 列出用户
POST /users # 创建用户
GET /users/123 # 获取单个用户
PUT /users/123 # 全量更新用户
PATCH /users/123 # 部分更新用户
DELETE /users/123 # 删除用户
undefinedNested Resources
嵌套资源
undefinedundefined✅ Logical nesting (max 2 levels)
✅ 合理嵌套(最多2层)
GET /users/123/orders # User's orders
GET /users/123/orders/456 # Specific order
POST /users/123/orders # Create order for user
GET /users/123/orders # 用户的订单
GET /users/123/orders/456 # 单个订单
POST /users/123/orders # 为用户创建订单
❌ Too deeply nested
❌ 嵌套过深
GET /users/123/orders/456/items/789/reviews
GET /users/123/orders/456/items/789/reviews
✅ Flatten when appropriate
✅ 适当扁平化
GET /order-items/789/reviews # Direct access
undefinedGET /order-items/789/reviews # 直接访问
undefinedHTTP Methods & Status Codes
HTTP方法与状态码
undefinedundefinedGET - Retrieve resource(s)
GET - 获取资源
GET /users → 200 OK + array
GET /users/123 → 200 OK + object
GET /users/999 → 404 Not Found
GET /users → 200 OK + 数组
GET /users/123 → 200 OK + 对象
GET /users/999 → 404 Not Found
POST - Create resource
POST - 创建资源
POST /users → 201 Created + object + Location header
POST /users (invalid) → 400 Bad Request + errors
POST /users → 201 Created + 对象 + Location请求头
POST /users (invalid) → 400 Bad Request + 错误信息
PUT - Full update (replace)
PUT - 全量更新(替换)
PUT /users/123 → 200 OK + updated object
PUT /users/999 → 404 Not Found
PUT /users/123 → 200 OK + 更新后的对象
PUT /users/999 → 404 Not Found
PATCH - Partial update
PATCH - 部分更新
PATCH /users/123 → 200 OK + updated object
PATCH /users/123 → 200 OK + 更新后的对象
DELETE - Remove resource
DELETE - 删除资源
DELETE /users/123 → 204 No Content
DELETE /users/999 → 404 Not Found
DELETE /users/123 → 204 No Content
DELETE /users/999 → 404 Not Found
Other common status codes
其他常见状态码
401 Unauthorized # Not authenticated
403 Forbidden # Authenticated but not authorized
409 Conflict # Resource state conflict
422 Unprocessable # Validation failed
429 Too Many Requests # Rate limited
500 Internal Error # Server error
503 Service Unavailable # Maintenance/overload
undefined401 Unauthorized # 未认证
403 Forbidden # 已认证但无权限
409 Conflict # 资源状态冲突
422 Unprocessable # 验证失败
429 Too Many Requests # 请求超限
500 Internal Error # 服务器错误
503 Service Unavailable # 维护/过载
undefinedError Response Format
错误响应格式
json
// ❌ Inconsistent error formats
{ "error": "Not found" }
{ "message": "Invalid email" }
{ "errors": ["Error 1", "Error 2"] }
// ✅ Consistent error envelope
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request contains invalid data",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Please provide a valid email address"
},
{
"field": "password",
"code": "TOO_SHORT",
"message": "Password must be at least 8 characters"
}
],
"request_id": "req_abc123"
}
}
// ✅ Not found error
{
"error": {
"code": "NOT_FOUND",
"message": "User with ID 123 not found",
"request_id": "req_def456"
}
}
// ✅ Server error (no sensitive details)
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred. Please try again.",
"request_id": "req_ghi789"
}
}json
// ❌ 不一致的错误格式
{ "error": "Not found" }
{ "message": "Invalid email" }
{ "errors": ["Error 1", "Error 2"] }
// ✅ 统一的错误封装
{
"error": {
"code": "VALIDATION_ERROR",
"message": "请求包含无效数据",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "请提供有效的邮箱地址"
},
{
"field": "password",
"code": "TOO_SHORT",
"message": "密码长度至少为8位"
}
],
"request_id": "req_abc123"
}
}
// ✅ 资源未找到错误
{
"error": {
"code": "NOT_FOUND",
"message": "ID为123的用户不存在",
"request_id": "req_def456"
}
}
// ✅ 服务器错误(不包含敏感信息)
{
"error": {
"code": "INTERNAL_ERROR",
"message": "发生意外错误,请重试。",
"request_id": "req_ghi789"
}
}Pagination
分页
json
// ✅ Offset-based pagination
GET /users?page=2&per_page=20
{
"data": [...],
"meta": {
"current_page": 2,
"per_page": 20,
"total_pages": 10,
"total_count": 195
},
"links": {
"first": "/users?page=1&per_page=20",
"prev": "/users?page=1&per_page=20",
"next": "/users?page=3&per_page=20",
"last": "/users?page=10&per_page=20"
}
}
// ✅ Cursor-based pagination (for large datasets)
GET /users?cursor=eyJpZCI6MTIzfQ&limit=20
{
"data": [...],
"meta": {
"has_more": true,
"next_cursor": "eyJpZCI6MTQzfQ"
},
"links": {
"next": "/users?cursor=eyJpZCI6MTQzfQ&limit=20"
}
}json
// ✅ 偏移分页
GET /users?page=2&per_page=20
{
"data": [...],
"meta": {
"current_page": 2,
"per_page": 20,
"total_pages": 10,
"total_count": 195
},
"links": {
"first": "/users?page=1&per_page=20",
"prev": "/users?page=1&per_page=20",
"next": "/users?page=3&per_page=20",
"last": "/users?page=10&per_page=20"
}
}
// ✅ 游标分页(适用于大数据集)
GET /users?cursor=eyJpZCI6MTIzfQ&limit=20
{
"data": [...],
"meta": {
"has_more": true,
"next_cursor": "eyJpZCI6MTQzfQ"
},
"links": {
"next": "/users?cursor=eyJpZCI6MTQzfQ&limit=20"
}
}Filtering & Sorting
过滤与排序
undefinedundefined✅ Query parameter filtering
✅ 查询参数过滤
GET /users?status=active
GET /users?role=admin&status=active
GET /users?created_after=2024-01-01
GET /users?status=active
GET /users?role=admin&status=active
GET /users?created_after=2024-01-01
✅ Sorting
✅ 排序
GET /users?sort=created_at # Ascending (default)
GET /users?sort=-created_at # Descending (prefix with -)
GET /users?sort=last_name,-created_at # Multiple fields
GET /users?sort=created_at # 升序(默认)
GET /users?sort=-created_at # 降序(前缀为-)
GET /users?sort=last_name,-created_at # 多字段排序
✅ Field selection (sparse fieldsets)
✅ 字段选择(稀疏字段集)
GET /users?fields=id,name,email
GET /users/123?fields=id,name,orders
GET /users?fields=id,name,email
GET /users/123?fields=id,name,orders
✅ Search
✅ 搜索
GET /users?q=john
GET /users?search=john@example
undefinedGET /users?q=john
GET /users?search=john@example
undefinedConsistent Response Structure
统一响应结构
json
// ✅ Single resource
GET /users/123
{
"data": {
"id": "123",
"type": "user",
"attributes": {
"name": "John Doe",
"email": "john@example.com",
"created_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"orders": {
"links": {
"related": "/users/123/orders"
}
}
}
}
}
// ✅ Collection
GET /users
{
"data": [
{ "id": "123", "type": "user", ... },
{ "id": "124", "type": "user", ... }
],
"meta": {
"total_count": 100
},
"links": {
"self": "/users?page=1",
"next": "/users?page=2"
}
}
// ✅ Simpler envelope (also acceptable)
{
"user": {
"id": "123",
"name": "John Doe"
}
}
{
"users": [...],
"pagination": {...}
}json
// ✅ 单个资源
GET /users/123
{
"data": {
"id": "123",
"type": "user",
"attributes": {
"name": "John Doe",
"email": "john@example.com",
"created_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"orders": {
"links": {
"related": "/users/123/orders"
}
}
}
}
}
// ✅ 资源集合
GET /users
{
"data": [
{ "id": "123", "type": "user", ... },
{ "id": "124", "type": "user", ... }
],
"meta": {
"total_count": 100
},
"links": {
"self": "/users?page=1",
"next": "/users?page=2"
}
}
// ✅ 简化封装(同样可接受)
{
"user": {
"id": "123",
"name": "John Doe"
}
}
{
"users": [...],
"pagination": {...}
}Versioning
版本控制
undefinedundefined✅ URL path versioning (recommended - explicit)
✅ URL路径版本控制(推荐 - 显式)
GET /api/v1/users
GET /api/v2/users
GET /api/v1/users
GET /api/v2/users
✅ Header versioning
✅ 请求头版本控制
GET /api/users
Accept: application/vnd.myapi.v2+json
GET /api/users
Accept: application/vnd.myapi.v2+json
✅ Query parameter (simple, but less clean)
✅ 查询参数版本控制(简单但不够简洁)
GET /api/users?version=2
undefinedGET /api/users?version=2
undefinedRate Limiting
请求频率限制
undefinedundefined✅ Include rate limit headers
✅ 包含频率限制响应头
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 998
X-RateLimit-Reset: 1640995200
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 998
X-RateLimit-Reset: 1640995200
✅ Rate limited response
✅ 请求超限响应
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Please retry after 60 seconds.",
"retry_after": 60
}
}
undefinedHTTP/1.1 429 Too Many Requests
Retry-After: 60
{
"error": {
"code": "RATE_LIMITED",
"message": "请求过于频繁,请60秒后重试。",
"retry_after": 60
}
}
undefinedActions on Resources
资源操作
undefinedundefinedFor non-CRUD actions, use sub-resources or actions
对于非CRUD操作,使用子资源或独立操作
✅ Sub-resource style
✅ 子资源风格
POST /users/123/activate
POST /orders/456/cancel
POST /posts/789/publish
POST /users/123/activate
POST /orders/456/cancel
POST /posts/789/publish
✅ Or controller-style for complex operations
✅ 复杂操作使用控制器风格
POST /auth/login
POST /auth/logout
POST /auth/refresh
POST /password/reset
POST /password/reset/confirm
undefinedPOST /auth/login
POST /auth/logout
POST /auth/refresh
POST /password/reset
POST /password/reset/confirm
undefinedRequest Validation
请求验证
json
// ✅ Validate and return all errors at once
POST /users
{
"email": "invalid",
"password": "short"
}
// Response: 422 Unprocessable Entity
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Must be a valid email address"
},
{
"field": "password",
"code": "TOO_SHORT",
"message": "Must be at least 8 characters",
"meta": {
"min_length": 8,
"actual_length": 5
}
}
]
}
}json
// ✅ 一次性返回所有验证错误
POST /users
{
"email": "invalid",
"password": "short"
}
// 响应: 422 Unprocessable Entity
{
"error": {
"code": "VALIDATION_ERROR",
"message": "验证失败",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "必须是有效的邮箱地址"
},
{
"field": "password",
"code": "TOO_SHORT",
"message": "长度至少为8位",
"meta": {
"min_length": 8,
"actual_length": 5
}
}
]
}
}HATEOAS (Hypermedia)
HATEOAS(超媒体)
json
// ✅ Include links for discoverability
{
"data": {
"id": "123",
"status": "pending",
"total": 99.99
},
"links": {
"self": "/orders/123",
"cancel": "/orders/123/cancel",
"pay": "/orders/123/pay",
"items": "/orders/123/items"
},
"actions": {
"cancel": {
"method": "POST",
"href": "/orders/123/cancel"
},
"pay": {
"method": "POST",
"href": "/orders/123/pay",
"fields": [
{ "name": "payment_method", "type": "string", "required": true }
]
}
}
}json
// ✅ 包含可发现的链接
{
"data": {
"id": "123",
"status": "pending",
"total": 99.99
},
"links": {
"self": "/orders/123",
"cancel": "/orders/123/cancel",
"pay": "/orders/123/pay",
"items": "/orders/123/items"
},
"actions": {
"cancel": {
"method": "POST",
"href": "/orders/123/cancel"
},
"pay": {
"method": "POST",
"href": "/orders/123/pay",
"fields": [
{ "name": "payment_method", "type": "string", "required": true }
]
}
}
}Bulk Operations
批量操作
json
// ✅ Bulk create
POST /users/bulk
{
"users": [
{ "name": "User 1", "email": "user1@example.com" },
{ "name": "User 2", "email": "user2@example.com" }
]
}
// Response with partial success
{
"data": {
"succeeded": [
{ "id": "123", "name": "User 1" }
],
"failed": [
{
"index": 1,
"error": {
"code": "DUPLICATE_EMAIL",
"message": "Email already exists"
}
}
]
},
"meta": {
"total": 2,
"succeeded": 1,
"failed": 1
}
}json
// ✅ 批量创建
POST /users/bulk
{
"users": [
{ "name": "User 1", "email": "user1@example.com" },
{ "name": "User 2", "email": "user2@example.com" }
]
}
// 部分成功的响应
{
"data": {
"succeeded": [
{ "id": "123", "name": "User 1" }
],
"failed": [
{
"index": 1,
"error": {
"code": "DUPLICATE_EMAIL",
"message": "邮箱已存在"
}
}
]
},
"meta": {
"total": 2,
"succeeded": 1,
"failed": 1
}
}Output Format
输出格式
When auditing APIs, output findings in this format:
endpoint - [category] Description of issueExample:
GET /getUsers - [rest] Use noun '/users' instead of verb '/getUsers'
POST /users - [error] Missing validation error details in 400 response
GET /users - [page] Missing pagination metadata in list response审计API时,请按以下格式输出结果:
endpoint - [类别] 问题描述示例:
GET /getUsers - [rest] 应使用名词'/users'而非动词'/getUsers'
POST /users - [error] 400响应中缺少验证错误详情
GET /users - [page] 列表响应中缺少分页元数据How to Use
使用方法
Read individual rule files for detailed explanations:
rules/rest-http-methods.md
rules/error-consistent-format.md
rules/page-cursor-based.md阅读单个规则文件获取详细说明:
rules/rest-http-methods.md
rules/error-consistent-format.md
rules/page-cursor-based.md