api-design-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

API Design Patterns

API设计模式

Resource Naming

资源命名

  • Use plural nouns:
    /users
    ,
    /orders
    ,
    /products
  • Nest for relationships:
    /users/{id}/orders
  • Max nesting depth: 2 levels. Beyond that, use query params or top-level resources
  • Use kebab-case:
    /user-profiles
    , not
    /userProfiles
  • Never put verbs in URLs:
    /users/{id}/activate
    is wrong, use
    POST /users/{id}/activation
  • 使用复数名词:
    /users
    /orders
    /products
  • 为关联关系使用嵌套结构:
    /users/{id}/orders
  • 最大嵌套深度:2层。超过此深度,使用查询参数或顶级资源
  • 使用短横线分隔(kebab-case):
    /user-profiles
    ,而非
    /userProfiles
  • 绝不要在URL中使用动词:
    /users/{id}/activate
    是错误的,应使用
    POST /users/{id}/activation

HTTP Methods

HTTP方法

MethodPurposeIdempotentRequest BodySuccess Code
GETRead resource(s)YesNo200
POSTCreate resourceNoYes201
PUTFull replaceYesYes200
PATCHPartial updateNoYes200
DELETERemove resourceYesNo204
Return
Location
header on POST with the URL of the created resource.
方法用途幂等性请求体成功状态码
GET读取资源(一个或多个)200
POST创建资源201
PUT完全替换资源200
PATCH部分更新200
DELETE删除资源204
POST请求成功后返回
Location
头,包含创建资源的URL。

Status Codes

状态码

200 OK              - Successful read/update
201 Created         - Successful creation
204 No Content      - Successful delete
400 Bad Request     - Validation error (include field-level errors)
401 Unauthorized    - Missing or invalid authentication
403 Forbidden       - Authenticated but not authorized
404 Not Found       - Resource does not exist
409 Conflict        - State conflict (duplicate, version mismatch)
422 Unprocessable   - Semantically invalid (valid JSON, bad values)
429 Too Many Reqs   - Rate limited (include Retry-After header)
500 Internal Error  - Unhandled server error (never expose stack traces)
200 OK              - 读取/更新成功
201 Created         - 创建成功
204 No Content      - 删除成功
400 Bad Request     - 验证错误(包含字段级错误)
401 Unauthorized    - 缺少或无效的身份认证
403 Forbidden       - 已认证但无权限
404 Not Found       - 资源不存在
409 Conflict        - 状态冲突(重复、版本不匹配)
422 Unprocessable   - 语义无效(JSON格式合法,但值不合法)
429 Too Many Reqs   - 请求超限(包含Retry-After头)
500 Internal Error  - 未处理的服务器错误(绝不要暴露堆栈跟踪)

Error Response Format

错误响应格式

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      { "field": "email", "message": "Must be a valid email address" },
      { "field": "age", "message": "Must be at least 18" }
    ]
  }
}
Use consistent error codes across the API. Document every code in your API reference.
json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      { "field": "email", "message": "Must be a valid email address" },
      { "field": "age", "message": "Must be at least 18" }
    ]
  }
}
在整个API中使用一致的错误码。在API参考文档中记录每个错误码。

Cursor-Based Pagination (preferred)

基于游标分页(推荐)

GET /users?limit=20&cursor=eyJpZCI6MTAwfQ

Response:
{
  "data": [...],
  "pagination": {
    "next_cursor": "eyJpZCI6MTIwfQ",
    "has_more": true
  }
}
Use cursor pagination for large or frequently changing datasets. Encode cursors as opaque base64 strings. Never expose raw IDs in cursors.
GET /users?limit=20&cursor=eyJpZCI6MTAwfQ

Response:
{
  "data": [...],
  "pagination": {
    "next_cursor": "eyJpZCI6MTIwfQ",
    "has_more": true
  }
}
对于大型或频繁变更的数据集,使用游标分页。将游标编码为不透明的base64字符串。绝不要在游标中暴露原始ID。

Offset-Based Pagination (simple cases only)

基于偏移量分页(仅适用于简单场景)

GET /users?page=3&per_page=20

Response:
{
  "data": [...],
  "pagination": {
    "page": 3,
    "per_page": 20,
    "total": 245,
    "total_pages": 13
  }
}
Only use offset pagination when total count is cheap and dataset is small.
GET /users?page=3&per_page=20

Response:
{
  "data": [...],
  "pagination": {
    "page": 3,
    "per_page": 20,
    "total": 245,
    "total_pages": 13
  }
}
仅当总计数获取成本低且数据集较小时,才使用偏移量分页。

Filtering and Sorting

过滤与排序

GET /orders?status=pending&created_after=2025-01-01&sort=-created_at,+total
GET /products?category=electronics&price_min=100&price_max=500
GET /users?search=john&fields=id,name,email
Use field selection (
fields
param) to reduce payload size. Prefix sort fields with
-
for descending.
GET /orders?status=pending&created_after=2025-01-01&sort=-created_at,+total
GET /products?category=electronics&price_min=100&price_max=500
GET /users?search=john&fields=id,name,email
使用字段选择(
fields
参数)来减少响应体大小。排序字段前缀加
-
表示降序。

Versioning

版本控制

Prefer URL path versioning for simplicity:
/api/v1/users
/api/v2/users
Rules:
  • Never break v1 once published. Add fields, never remove them.
  • New required fields = new version
  • Deprecate old versions with
    Sunset
    header and 6-month notice
  • Support at most 2 active versions simultaneously
推荐使用URL路径版本控制以简化操作:
/api/v1/users
/api/v2/users
规则:
  • 一旦发布,绝不要破坏v1版本。可以添加字段,但绝不要删除字段。
  • 新增必填字段 = 新版本
  • 使用
    Sunset
    头和6个月的通知来弃用旧版本
  • 同时最多支持2个活跃版本

Request/Response Headers

请求/响应头

Content-Type: application/json
Accept: application/json
Authorization: Bearer <token>
X-Request-Id: <uuid>          # For tracing
X-RateLimit-Limit: 100        # Requests per window
X-RateLimit-Remaining: 47     # Remaining in window
X-RateLimit-Reset: 1700000000 # Window reset Unix timestamp
Retry-After: 30               # Seconds until rate limit resets
Always return
X-Request-Id
in responses for debugging.
Content-Type: application/json
Accept: application/json
Authorization: Bearer <token>
X-Request-Id: <uuid>          # 用于追踪
X-RateLimit-Limit: 100        # 窗口期内最大请求数
X-RateLimit-Remaining: 47     # 窗口期内剩余请求数
X-RateLimit-Reset: 1700000000 # 窗口期重置的Unix时间戳
Retry-After: 30               # 限流重置前的等待秒数
始终在响应中返回
X-Request-Id
用于调试。

OpenAPI Spec Guidelines

OpenAPI规范指南

  • Write spec first, then implement (spec-driven development)
  • Use
    $ref
    for shared schemas:
    $ref: '#/components/schemas/User'
  • Define
    examples
    for every endpoint
  • Use
    oneOf
    /
    anyOf
    for polymorphic responses
  • Generate client SDKs from the spec, never hand-write them
  • Validate requests against the spec in middleware
yaml
paths:
  /users/{id}:
    get:
      operationId: getUser
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: User found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          $ref: '#/components/responses/NotFound'
  • 先编写规范,再实现(规范驱动开发)
  • 对共享模式使用
    $ref
    $ref: '#/components/schemas/User'
  • 为每个端点定义
    examples
  • 对多态响应使用
    oneOf
    /
    anyOf
  • 从规范生成客户端SDK,绝不要手写
  • 在中间件中根据规范验证请求
yaml
paths:
  /users/{id}:
    get:
      operationId: getUser
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: User found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          $ref: '#/components/responses/NotFound'

Rate Limiting Strategy

限流策略

  • Apply per-user, per-endpoint limits
  • Use sliding window algorithm (not fixed window)
  • Return
    429
    with
    Retry-After
    header
  • Exempt health check and auth endpoints from rate limits
  • Log rate-limited requests for abuse detection
  • 按每个用户、每个端点应用限流
  • 使用滑动窗口算法(而非固定窗口)
  • 返回
    429
    状态码并附带
    Retry-After
  • 健康检查和认证端点豁免限流
  • 记录被限流的请求以检测滥用