api-design-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

API 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

快速参考

TopicLoad reference
Design Process
skills/api-design-patterns/references/design-process.md
主题参考路径
设计流程
skills/api-design-patterns/references/design-process.md

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   /deleteUser
Use 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 changes
GET /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 differences
GET /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 compatibility
GET /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 UIs
GET /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 scroll
GET /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 data
GET /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_EXCEEDED

Filtering 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 descending
GET /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==electronics
GET /users?filter=status==active;role==admin,role==moderator
               # 分号表示AND,逗号表示OR

GET /products?filter=price>100;price<500;category==electronics

Full-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
undefined
GET /users/123?fields=id,name,profile(avatar,bio)
优势:
  • 减少响应体大小
  • 提升响应速度
  • 降低带宽消耗
  • 优化移动端性能
undefined

HATEOAS (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: 3600
http
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 742
X-RateLimit-Reset: 1705320000
Retry-After: 3600

Standard (RFC 6585)

标准规范(RFC 6585)

RateLimit-Limit: 1000 RateLimit-Remaining: 742 RateLimit-Reset: 3600
undefined
RateLimit-Limit: 1000 RateLimit-Remaining: 742 RateLimit-Reset: 3600
undefined

Authentication 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, microservices
http
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 APIs
http
X-API-Key: ak_live_a3f7c9b2d8e1f4g6h9

优点:简单,服务端易管理
缺点:安全性较低,权限范围难控制
适用场景:内部服务,管理后台API

Basic Auth

基础认证

http
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

Pros: Simple, built-in browser support
Cons: Credentials in every request
When: Internal tools, development only
http
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

undefined
undefined

Natural Idempotency

天然幂等性

PUT /users/123          # Always idempotent
DELETE /users/123       # Idempotent (404 on repeat)
POST /users/123/follow  # Use PUT for idempotency
PUT /users/123          # 始终幂等
DELETE /users/123       # 幂等(重复请求返回404)
POST /users/123/follow  # 使用PUT实现幂等性

Caching Strategies

缓存策略

ETags (Conditional Requests)

ETags(条件请求)

http
undefined
http
undefined

Initial 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
undefined
304 Not Modified
undefined

Cache-Control Headers

Cache-Control头部

http
undefined
http
undefined

Never 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
undefined
Cache-Control: public, max-age=31536000, immutable
undefined

GraphQL 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

最佳实践总结

  1. Consistency: Follow conventions across all endpoints
  2. Versioning: Plan deprecation strategy from day one
  3. Documentation: Use OpenAPI/GraphQL schemas, keep updated
  4. Error Handling: Detailed, actionable error messages with codes
  5. Security: Always use HTTPS, validate inputs, rate limit
  6. Performance: Implement caching, pagination, field selection
  7. Monitoring: Log request IDs, track latency and error rates
  8. Backward Compatibility: Additive changes only within versions
  9. Testing: Contract tests, integration tests, load tests
  10. Documentation: Interactive docs (Swagger UI, GraphQL Playground)
  1. 一致性:所有端点遵循统一规范
  2. 版本控制:从项目初期规划弃用策略
  3. 文档:使用OpenAPI/GraphQL schema,并保持更新
  4. 错误处理:提供详细、可操作的错误信息和错误码
  5. 安全性:始终使用HTTPS,验证输入,限制请求频率
  6. 性能:实现缓存、分页和字段选择
  7. 监控:记录请求ID,跟踪延迟和错误率
  8. 向后兼容:版本内仅做新增式变更
  9. 测试:契约测试、集成测试、负载测试
  10. 文档:提供交互式文档(Swagger UI、GraphQL Playground)

Anti-Patterns to Avoid

需避免的反模式

  1. Chatty APIs: Too many round trips (use batching, GraphQL)
  2. Over-fetching: Returning unnecessary data (use field selection)
  3. Under-fetching: Requiring multiple calls (use includes/embeds)
  4. Leaking Implementation: Exposing DB structure in API
  5. Poor Error Messages: Generic errors without details
  6. Breaking Changes: Modifying existing fields without versioning
  7. No Rate Limiting: Allowing resource exhaustion
  8. Missing Documentation: Undocumented endpoints and parameters
  9. Inconsistent Naming: Mixed conventions across endpoints
  10. Ignoring HTTP Semantics: Misusing status codes and methods
  1. 频繁调用的API:过多的网络往返(使用批量处理、GraphQL)
  2. 过度获取:返回不必要的数据(使用字段选择)
  3. 获取不足:需要多次调用才能获取完整数据(使用包含/嵌入)
  4. 暴露实现细节:在API中暴露数据库结构
  5. 模糊的错误信息:无详细信息的通用错误
  6. 破坏性变更:未做版本控制就修改现有字段
  7. 无请求频率限制:允许资源耗尽
  8. 缺失文档:未记录的端点和参数
  9. 命名不一致:端点间混合使用不同规范
  10. 忽略HTTP语义:错误使用状态码和请求方法

Resources

参考资源