api-design-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAPI Design Patterns
API设计模式
Expert guidance for designing scalable, maintainable REST and GraphQL APIs with industry-standard patterns for versioning, pagination, error handling, authentication, and service contracts.
为设计可扩展、可维护的REST与GraphQL API提供专业指导,涵盖版本控制、分页、错误处理、认证和服务契约等行业标准模式。
When to Use This Skill
适用场景
- Designing new REST or GraphQL APIs from scratch
- Refactoring existing APIs for better scalability and consistency
- Defining service contracts for microservices architectures
- Implementing versioning strategies for API evolution
- Standardizing error handling and response formats across services
- Designing pagination for large datasets
- Implementing HATEOAS or hypermedia-driven APIs
- Creating API specifications (OpenAPI, GraphQL Schema)
- 从零开始设计新的REST或GraphQL API
- 重构现有API以提升可扩展性和一致性
- 为微服务架构定义服务契约
- 实现API演进的版本控制策略
- 标准化跨服务的错误处理和响应格式
- 为大型数据集设计分页机制
- 实现HATEOAS或超媒体驱动的API
- 创建API规范(OpenAPI、GraphQL Schema)
Quick Reference
快速参考
| Topic | Load reference |
|---|---|
| Design Process | |
| 主题 | 参考路径 |
|---|---|
| 设计流程 | |
Core Principles
核心原则
1. Resource-Oriented Design (REST)
1. 面向资源的设计(REST)
URLs represent resources, not actions:
✓ GET /users/123
✓ POST /users
✓ PUT /users/123
✓ DELETE /users/123
✗ GET /getUser?id=123
✗ POST /createUser
✗ POST /deleteUserUse HTTP methods semantically:
- GET: Retrieve resource(s), idempotent, cacheable
- POST: Create resource, non-idempotent
- PUT: Replace entire resource, idempotent
- PATCH: Partial update, idempotent
- DELETE: Remove resource, idempotent
URL代表资源而非操作:
✓ GET /users/123
✓ POST /users
✓ PUT /users/123
✓ DELETE /users/123
✗ GET /getUser?id=123
✗ POST /createUser
✗ POST /deleteUser语义化使用HTTP方法:
- GET:获取资源,幂等,可缓存
- POST:创建资源,非幂等
- PUT:替换整个资源,幂等
- PATCH:部分更新,幂等
- DELETE:删除资源,幂等
2. Consistent Naming Conventions
2. 一致的命名规范
Resources: /users, /orders, /products (plural nouns)
Nested: /users/123/orders
Collections: /users?status=active&page=2
Sub-resources: /users/123/settings
Actions (rare): /users/123/activate (POST)资源: /users, /orders, /products(复数名词)
嵌套资源: /users/123/orders
集合资源: /users?status=active&page=2
子资源: /users/123/settings
操作(罕见): /users/123/activate(POST)3. HTTP Status Codes
3. HTTP状态码
Success:
- 200 OK: Standard response for GET, PUT, PATCH
- 201 Created: Resource created (POST), return Location header
- 202 Accepted: Async processing started
- 204 No Content: Success with no response body (DELETE)
Client Errors:
- 400 Bad Request: Invalid syntax or validation failure
- 401 Unauthorized: Authentication required or failed
- 403 Forbidden: Authenticated but insufficient permissions
- 404 Not Found: Resource doesn't exist
- 409 Conflict: State conflict (duplicate, version mismatch)
- 422 Unprocessable Entity: Semantic validation failure
- 429 Too Many Requests: Rate limit exceeded
Server Errors:
- 500 Internal Server Error: Unexpected server failure
- 502 Bad Gateway: Upstream service failure
- 503 Service Unavailable: Temporary overload or maintenance
- 504 Gateway Timeout: Upstream timeout
成功响应:
- 200 OK:GET、PUT、PATCH请求的标准响应
- 201 Created:资源创建成功(POST),返回Location头部
- 202 Accepted:异步处理已启动
- 204 No Content:操作成功但无响应体(DELETE)
客户端错误:
- 400 Bad Request:请求语法无效或验证失败
- 401 Unauthorized:需要认证或认证失败
- 403 Forbidden:已认证但权限不足
- 404 Not Found:资源不存在
- 409 Conflict:状态冲突(重复数据、版本不匹配)
- 422 Unprocessable Entity:语义验证失败
- 429 Too Many Requests:超出请求频率限制
服务器错误:
- 500 Internal Server Error:服务器意外故障
- 502 Bad Gateway:上游服务故障
- 503 Service Unavailable:服务器临时过载或维护中
- 504 Gateway Timeout:上游服务超时
Versioning Strategies
版本控制策略
URI Versioning (Most Common)
URI版本控制(最常用)
GET /v1/users/123
GET /v2/users/123
Pros: Clear, easy to route, browser-testable
Cons: URL proliferation, cache fragmentation
When: Public APIs, major breaking changesGET /v1/users/123
GET /v2/users/123
优点:清晰易懂,易于路由,可通过浏览器测试
缺点:URL数量膨胀,缓存碎片化
适用场景:公开API,重大破坏性变更Header Versioning
请求头版本控制
GET /users/123
Accept: application/vnd.myapi.v2+json
Pros: Clean URLs, content negotiation
Cons: Harder to test, caching complexity
When: Internal APIs, minor version differencesGET /users/123
Accept: application/vnd.myapi.v2+json
优点:URL简洁,支持内容协商
缺点:测试难度高,缓存复杂度高
适用场景:内部API,小版本差异Query Parameter Versioning
查询参数版本控制
GET /users/123?version=2
Pros: Simple, backward compatible
Cons: Pollutes query space, inconsistent
When: Rare, legacy compatibilityGET /users/123?version=2
优点:简单,向后兼容
缺点:污染查询参数空间,一致性差
适用场景:罕见场景,遗留系统兼容Deprecation Headers
弃用头部
http
Sunset: Sat, 31 Dec 2024 23:59:59 GMT
Deprecation: true
Link: <https://api.example.com/v2/users/123>; rel="successor-version"http
Sunset: Sat, 31 Dec 2024 23:59:59 GMT
Deprecation: true
Link: <https://api.example.com/v2/users/123>; rel="successor-version"Pagination Patterns
分页模式
Offset-Based Pagination
基于偏移量的分页
GET /users?limit=20&offset=40
Response:
{
"data": [...],
"pagination": {
"limit": 20,
"offset": 40,
"total": 1543
},
"links": {
"next": "/users?limit=20&offset=60",
"prev": "/users?limit=20&offset=20"
}
}
Pros: Simple, predictable, supports total count
Cons: Inconsistent with concurrent writes, performance degrades
When: Small datasets, stable data, admin UIsGET /users?limit=20&offset=40
响应:
{
"data": [...],
"pagination": {
"limit": 20,
"offset": 40,
"total": 1543
},
"links": {
"next": "/users?limit=20&offset=60",
"prev": "/users?limit=20&offset=20"
}
}
优点:简单直观,支持总计数
缺点:并发写入时数据不一致,性能随偏移量增大下降
适用场景:小型数据集,稳定数据,管理后台Cursor-Based Pagination
基于游标(Cursor)的分页
GET /users?limit=20&cursor=eyJpZCI6MTIzfQ
Response:
{
"data": [...],
"pagination": {
"next_cursor": "eyJpZCI6MTQzfQ",
"has_more": true
},
"links": {
"next": "/users?limit=20&cursor=eyJpZCI6MTQzfQ"
}
}
Pros: Consistent with writes, scalable, efficient
Cons: No total count, can't jump to arbitrary page
When: Large datasets, real-time feeds, infinite scrollGET /users?limit=20&cursor=eyJpZCI6MTIzfQ
响应:
{
"data": [...],
"pagination": {
"next_cursor": "eyJpZCI6MTQzfQ",
"has_more": true
},
"links": {
"next": "/users?limit=20&cursor=eyJpZCI6MTQzfQ"
}
}
优点:并发写入时数据一致,可扩展,性能高效
缺点:无总计数,无法跳转到任意页码
适用场景:大型数据集,实时信息流,无限滚动Keyset Pagination (Seek Method)
基于键集的分页(Seek方法)
GET /users?limit=20&after_id=123&created_after=2024-01-01T00:00:00Z
Pros: Most performant, index-friendly
Cons: Requires sortable field, complex queries
When: Very large datasets, time-series dataGET /users?limit=20&after_id=123&created_after=2024-01-01T00:00:00Z
优点:性能最优,索引友好
缺点:需要可排序字段,查询逻辑复杂
适用场景:超大型数据集,时间序列数据Error Response Format
错误响应格式
Standard Error Schema
标准错误 schema
json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Email format is invalid"
},
{
"field": "age",
"code": "OUT_OF_RANGE",
"message": "Age must be between 18 and 120"
}
],
"request_id": "req_a3f7c9b2",
"timestamp": "2024-01-15T10:30:00Z",
"documentation_url": "https://docs.api.com/errors/VALIDATION_ERROR"
}
}json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "请求验证失败",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "邮箱格式无效"
},
{
"field": "age",
"code": "OUT_OF_RANGE",
"message": "年龄必须在18到120之间"
}
],
"request_id": "req_a3f7c9b2",
"timestamp": "2024-01-15T10:30:00Z",
"documentation_url": "https://docs.api.com/errors/VALIDATION_ERROR"
}
}Error Code Patterns
错误码规范
Format: CATEGORY_SPECIFIC_REASON
Authentication:
- AUTH_MISSING_TOKEN
- AUTH_INVALID_TOKEN
- AUTH_EXPIRED_TOKEN
Authorization:
- AUTHZ_INSUFFICIENT_PERMISSIONS
- AUTHZ_RESOURCE_FORBIDDEN
Validation:
- VALIDATION_MISSING_FIELD
- VALIDATION_INVALID_FORMAT
- VALIDATION_OUT_OF_RANGE
Business Logic:
- BUSINESS_DUPLICATE_EMAIL
- BUSINESS_INSUFFICIENT_BALANCE
- BUSINESS_OPERATION_NOT_ALLOWED
System:
- SYSTEM_INTERNAL_ERROR
- SYSTEM_SERVICE_UNAVAILABLE
- SYSTEM_RATE_LIMIT_EXCEEDED格式:分类_具体原因
认证相关:
- AUTH_MISSING_TOKEN
- AUTH_INVALID_TOKEN
- AUTH_EXPIRED_TOKEN
授权相关:
- AUTHZ_INSUFFICIENT_PERMISSIONS
- AUTHZ_RESOURCE_FORBIDDEN
验证相关:
- VALIDATION_MISSING_FIELD
- VALIDATION_INVALID_FORMAT
- VALIDATION_OUT_OF_RANGE
业务逻辑相关:
- BUSINESS_DUPLICATE_EMAIL
- BUSINESS_INSUFFICIENT_BALANCE
- BUSINESS_OPERATION_NOT_ALLOWED
系统相关:
- SYSTEM_INTERNAL_ERROR
- SYSTEM_SERVICE_UNAVAILABLE
- SYSTEM_RATE_LIMIT_EXCEEDEDFiltering and Searching
过滤与搜索
Query Parameters for Filtering
基于查询参数的过滤
GET /users?status=active&role=admin&created_after=2024-01-01
GET /users?search=john&fields=name,email
GET /users?sort=-created_at,name # - prefix for descendingGET /users?status=active&role=admin&created_after=2024-01-01
GET /users?search=john&fields=name,email
GET /users?sort=-created_at,name # 前缀-表示降序Complex Filtering (FIQL/RSQL)
复杂过滤(FIQL/RSQL)
GET /users?filter=status==active;role==admin,role==moderator
# AND between semicolons, OR between commas
GET /products?filter=price>100;price<500;category==electronicsGET /users?filter=status==active;role==admin,role==moderator
# 分号表示AND,逗号表示OR
GET /products?filter=price>100;price<500;category==electronicsFull-Text Search
全文搜索
GET /users?q=john+smith&fields=name,bio,company
Response includes relevance scoring:
{
"data": [
{
"id": 123,
"name": "John Smith",
"_score": 0.95
}
]
}GET /users?q=john+smith&fields=name,bio,company
响应包含相关性评分:
{
"data": [
{
"id": 123,
"name": "John Smith",
"_score": 0.95
}
]
}Field Selection (Sparse Fieldsets)
字段选择(稀疏字段集)
GET /users/123?fields=id,name,email
Response:
{
"id": 123,
"name": "John Doe",
"email": "john@example.com"
}GET /users/123?fields=id,name,email
响应:
{
"id": 123,
"name": "John Doe",
"email": "john@example.com"
}Nested resources
嵌套资源
GET /users/123?fields=id,name,profile(avatar,bio)
Benefits:
- Reduced payload size
- Faster response times
- Lower bandwidth consumption
- Better mobile performance
undefinedGET /users/123?fields=id,name,profile(avatar,bio)
优势:
- 减少响应体大小
- 提升响应速度
- 降低带宽消耗
- 优化移动端性能
undefinedHATEOAS (Hypermedia)
HATEOAS(超媒体)
HAL (Hypertext Application Language)
HAL(超文本应用语言)
json
{
"id": 123,
"name": "John Doe",
"email": "john@example.com",
"_links": {
"self": { "href": "/users/123" },
"orders": { "href": "/users/123/orders" },
"update": { "href": "/users/123", "method": "PUT" },
"delete": { "href": "/users/123", "method": "DELETE" }
},
"_embedded": {
"recent_orders": [
{
"id": 456,
"total": 99.99,
"_links": {
"self": { "href": "/orders/456" }
}
}
]
}
}json
{
"id": 123,
"name": "John Doe",
"email": "john@example.com",
"_links": {
"self": { "href": "/users/123" },
"orders": { "href": "/users/123/orders" },
"update": { "href": "/users/123", "method": "PUT" },
"delete": { "href": "/users/123", "method": "DELETE" }
},
"_embedded": {
"recent_orders": [
{
"id": 456,
"total": 99.99,
"_links": {
"self": { "href": "/orders/456" }
}
}
]
}
}JSON:API Format
JSON:API格式
json
{
"data": {
"type": "users",
"id": "123",
"attributes": {
"name": "John Doe",
"email": "john@example.com"
},
"relationships": {
"orders": {
"links": {
"self": "/users/123/relationships/orders",
"related": "/users/123/orders"
}
}
},
"links": {
"self": "/users/123"
}
}
}json
{
"data": {
"type": "users",
"id": "123",
"attributes": {
"name": "John Doe",
"email": "john@example.com"
},
"relationships": {
"orders": {
"links": {
"self": "/users/123/relationships/orders",
"related": "/users/123/orders"
}
}
},
"links": {
"self": "/users/123"
}
}
}Rate Limiting Headers
请求频率限制头部
http
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 742
X-RateLimit-Reset: 1705320000
Retry-After: 3600http
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 742
X-RateLimit-Reset: 1705320000
Retry-After: 3600Standard (RFC 6585)
标准规范(RFC 6585)
RateLimit-Limit: 1000
RateLimit-Remaining: 742
RateLimit-Reset: 3600
undefinedRateLimit-Limit: 1000
RateLimit-Remaining: 742
RateLimit-Reset: 3600
undefinedAuthentication Patterns
认证模式
Bearer Token (OAuth 2.0, JWT)
Bearer令牌(OAuth 2.0、JWT)
http
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Pros: Stateless, scalable, standard
Cons: Token size, revocation complexity
When: Modern APIs, microserviceshttp
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
优点:无状态,可扩展,标准化
缺点:令牌体积大,撤销逻辑复杂
适用场景:现代API,微服务API Key
API密钥
http
X-API-Key: ak_live_a3f7c9b2d8e1f4g6h9
Pros: Simple, server-side management
Cons: Less secure, harder to scope
When: Internal services, admin APIshttp
X-API-Key: ak_live_a3f7c9b2d8e1f4g6h9
优点:简单,服务端易管理
缺点:安全性较低,权限范围难控制
适用场景:内部服务,管理后台APIBasic Auth
基础认证
http
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Pros: Simple, built-in browser support
Cons: Credentials in every request
When: Internal tools, development onlyhttp
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
优点:简单,浏览器原生支持
缺点:每次请求都携带凭证
适用场景:内部工具,开发环境Idempotency
幂等性
Idempotency Keys (POST)
幂等性密钥(POST请求)
http
POST /payments
Idempotency-Key: a3f7c9b2-d8e1-4f6g-h9i0-j1k2l3m4n5o6
Content-Type: application/json
{
"amount": 100.00,
"currency": "USD",
"description": "Payment for order #123"
}http
POST /payments
Idempotency-Key: a3f7c9b2-d8e1-4f6g-h9i0-j1k2l3m4n5o6
Content-Type: application/json
{
"amount": 100.00,
"currency": "USD",
"description": "订单#123的付款"
}Server stores key + response for 24 hours
服务器将密钥和响应存储24小时
Duplicate requests return cached response with 200 OK
重复请求返回缓存的响应,状态码200 OK
undefinedundefinedNatural Idempotency
天然幂等性
PUT /users/123 # Always idempotent
DELETE /users/123 # Idempotent (404 on repeat)
POST /users/123/follow # Use PUT for idempotencyPUT /users/123 # 始终幂等
DELETE /users/123 # 幂等(重复请求返回404)
POST /users/123/follow # 使用PUT实现幂等性Caching Strategies
缓存策略
ETags (Conditional Requests)
ETags(条件请求)
http
undefinedhttp
undefinedInitial request
首次请求
GET /users/123
ETag: "a3f7c9b2"
GET /users/123
ETag: "a3f7c9b2"
Subsequent request
后续请求
GET /users/123
If-None-Match: "a3f7c9b2"
GET /users/123
If-None-Match: "a3f7c9b2"
Response if unchanged:
资源未修改时的响应:
304 Not Modified
undefined304 Not Modified
undefinedCache-Control Headers
Cache-Control头部
http
undefinedhttp
undefinedNever cache
永不缓存
Cache-Control: no-store
Cache-Control: no-store
Cache for 1 hour, revalidate
缓存1小时,需重新验证
Cache-Control: max-age=3600, must-revalidate
Cache-Control: max-age=3600, must-revalidate
Cache forever (immutable)
永久缓存(不可变资源)
Cache-Control: public, max-age=31536000, immutable
undefinedCache-Control: public, max-age=31536000, immutable
undefinedGraphQL Patterns
GraphQL模式
Query Structure
查询结构
graphql
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
orders(first: 10) {
edges {
node {
id
total
status
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}graphql
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
orders(first: 10) {
edges {
node {
id
total
status
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}Error Handling
错误处理
json
{
"data": {
"user": null
},
"errors": [
{
"message": "User not found",
"locations": [{ "line": 2, "column": 3 }],
"path": ["user"],
"extensions": {
"code": "NOT_FOUND",
"userId": "123"
}
}
]
}json
{
"data": {
"user": null
},
"errors": [
{
"message": "用户不存在",
"locations": [{ "line": 2, "column": 3 }],
"path": ["user"],
"extensions": {
"code": "NOT_FOUND",
"userId": "123"
}
}
]
}Mutation Patterns
变更模式
graphql
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
user {
id
name
email
}
errors {
field
message
}
}
}graphql
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
user {
id
name
email
}
errors {
field
message
}
}
}Best Practices Summary
最佳实践总结
- Consistency: Follow conventions across all endpoints
- Versioning: Plan deprecation strategy from day one
- Documentation: Use OpenAPI/GraphQL schemas, keep updated
- Error Handling: Detailed, actionable error messages with codes
- Security: Always use HTTPS, validate inputs, rate limit
- Performance: Implement caching, pagination, field selection
- Monitoring: Log request IDs, track latency and error rates
- Backward Compatibility: Additive changes only within versions
- Testing: Contract tests, integration tests, load tests
- Documentation: Interactive docs (Swagger UI, GraphQL Playground)
- 一致性:所有端点遵循统一规范
- 版本控制:从项目初期规划弃用策略
- 文档:使用OpenAPI/GraphQL schema,并保持更新
- 错误处理:提供详细、可操作的错误信息和错误码
- 安全性:始终使用HTTPS,验证输入,限制请求频率
- 性能:实现缓存、分页和字段选择
- 监控:记录请求ID,跟踪延迟和错误率
- 向后兼容:版本内仅做新增式变更
- 测试:契约测试、集成测试、负载测试
- 文档:提供交互式文档(Swagger UI、GraphQL Playground)
Anti-Patterns to Avoid
需避免的反模式
- Chatty APIs: Too many round trips (use batching, GraphQL)
- Over-fetching: Returning unnecessary data (use field selection)
- Under-fetching: Requiring multiple calls (use includes/embeds)
- Leaking Implementation: Exposing DB structure in API
- Poor Error Messages: Generic errors without details
- Breaking Changes: Modifying existing fields without versioning
- No Rate Limiting: Allowing resource exhaustion
- Missing Documentation: Undocumented endpoints and parameters
- Inconsistent Naming: Mixed conventions across endpoints
- Ignoring HTTP Semantics: Misusing status codes and methods
- 频繁调用的API:过多的网络往返(使用批量处理、GraphQL)
- 过度获取:返回不必要的数据(使用字段选择)
- 获取不足:需要多次调用才能获取完整数据(使用包含/嵌入)
- 暴露实现细节:在API中暴露数据库结构
- 模糊的错误信息:无详细信息的通用错误
- 破坏性变更:未做版本控制就修改现有字段
- 无请求频率限制:允许资源耗尽
- 缺失文档:未记录的端点和参数
- 命名不一致:端点间混合使用不同规范
- 忽略HTTP语义:错误使用状态码和请求方法
Resources
参考资源
- REST: Roy Fielding's dissertation, RFC 7231 (HTTP semantics)
- OpenAPI: https://spec.openapis.org/oas/latest.html
- GraphQL: https://graphql.org/learn/
- HAL: https://stateless.group/hal_specification.html
- JSON:API: https://jsonapi.org/
- RFC 7807: Problem Details for HTTP APIs
- REST:Roy Fielding的博士论文、RFC 7231(HTTP语义)
- OpenAPI:https://spec.openapis.org/oas/latest.html
- GraphQL:https://graphql.org/learn/
- HAL:https://stateless.group/hal_specification.html
- JSON:API:https://jsonapi.org/
- RFC 7807:HTTP API的问题详情规范