api-design-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

API 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

按优先级划分的规则类别

PriorityCategoryImpactPrefix
1Resource DesignCRITICAL
rest-
2Error HandlingCRITICAL
error-
3SecurityCRITICAL
sec-
4Pagination & FilteringHIGH
page-
5VersioningHIGH
ver-
6Response FormatMEDIUM
resp-
7DocumentationMEDIUM
doc-
优先级类别影响程度前缀
1资源设计关键
rest-
2错误处理关键
error-
3安全关键
sec-
4分页与过滤
page-
5版本控制
ver-
6响应格式
resp-
7文档
doc-

Quick Reference

快速参考

1. Resource Design (CRITICAL)

1. 资源设计(关键)

  • rest-nouns-not-verbs
    - Use nouns for endpoints
  • rest-plural-resources
    - Use plural resource names
  • rest-http-methods
    - Correct HTTP method usage
  • rest-nested-resources
    - Proper resource nesting
  • rest-status-codes
    - Appropriate status codes
  • rest-idempotency
    - Idempotent operations
  • rest-hateoas
    - Hypermedia links
  • rest-nouns-not-verbs
    - 端点使用名词
  • rest-plural-resources
    - 资源名称使用复数形式
  • rest-http-methods
    - 正确使用HTTP方法
  • rest-nested-resources
    - 合理的资源嵌套
  • rest-status-codes
    - 使用恰当的状态码
  • rest-idempotency
    - 幂等操作
  • rest-hateoas
    - 超媒体链接

2. Error Handling (CRITICAL)

2. 错误处理(关键)

  • error-consistent-format
    - Consistent error structure
  • error-meaningful-messages
    - Helpful error messages
  • error-validation-details
    - Field-level validation errors
  • error-codes
    - Machine-readable error codes
  • error-stack-traces
    - Never expose in production
  • error-consistent-format
    - 统一的错误结构
  • error-meaningful-messages
    - 有意义的错误提示
  • error-validation-details
    - 字段级验证错误
  • error-codes
    - 机器可读的错误码
  • error-stack-traces
    - 生产环境绝不暴露堆栈跟踪

3. Security (CRITICAL)

3. 安全(关键)

  • sec-authentication
    - Proper auth implementation
  • sec-authorization
    - Resource-level permissions
  • sec-rate-limiting
    - Prevent abuse
  • sec-input-validation
    - Validate all input
  • sec-cors
    - CORS configuration
  • sec-sensitive-data
    - Protect sensitive data
  • sec-authentication
    - 正确实现认证
  • sec-authorization
    - 资源级权限控制
  • sec-rate-limiting
    - 防止滥用
  • sec-input-validation
    - 验证所有输入
  • sec-cors
    - CORS配置
  • sec-sensitive-data
    - 保护敏感数据

4. Pagination & Filtering (HIGH)

4. 分页与过滤(高)

  • page-cursor-based
    - Cursor pagination for large datasets
  • page-offset-based
    - Offset pagination for simple cases
  • page-consistent-params
    - Consistent parameter names
  • page-metadata
    - Include pagination metadata
  • filter-query-params
    - Filter via query parameters
  • sort-flexible
    - Flexible sorting options
  • page-cursor-based
    - 大数据集使用游标分页
  • page-offset-based
    - 简单场景使用偏移分页
  • page-consistent-params
    - 统一的参数命名
  • page-metadata
    - 包含分页元数据
  • filter-query-params
    - 通过查询参数实现过滤
  • sort-flexible
    - 灵活的排序选项

5. Versioning (HIGH)

5. 版本控制(高)

  • ver-url-path
    - Version in URL path
  • ver-header-based
    - Version in headers
  • ver-backward-compatible
    - Maintain compatibility
  • ver-deprecation
    - Deprecation strategy
  • ver-url-path
    - URL路径中包含版本
  • ver-header-based
    - 请求头中包含版本
  • ver-backward-compatible
    - 保持向后兼容
  • ver-deprecation
    - 弃用策略

6. Response Format (MEDIUM)

6. 响应格式(中)

  • resp-consistent-structure
    - Consistent response envelope
  • resp-json-conventions
    - JSON naming conventions
  • resp-partial-responses
    - Field selection
  • resp-compression
    - Response compression
  • resp-consistent-structure
    - 统一的响应封装
  • resp-json-conventions
    - JSON命名规范
  • resp-partial-responses
    - 字段选择
  • resp-compression
    - 响应压缩

7. Documentation (MEDIUM)

7. 文档(中)

  • doc-openapi
    - OpenAPI/Swagger spec
  • doc-examples
    - Request/response examples
  • doc-changelog
    - API changelog
  • doc-openapi
    - OpenAPI/Swagger规范
  • doc-examples
    - 请求/响应示例
  • doc-changelog
    - API变更日志

Essential Guidelines

核心指南

Resource Naming

资源命名

undefined
undefined

❌ 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
undefined
GET /users # 列出用户 POST /users # 创建用户 GET /users/123 # 获取单个用户 PUT /users/123 # 全量更新用户 PATCH /users/123 # 部分更新用户 DELETE /users/123 # 删除用户
undefined

Nested Resources

嵌套资源

undefined
undefined

✅ 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
undefined
GET /order-items/789/reviews # 直接访问
undefined

HTTP Methods & Status Codes

HTTP方法与状态码

undefined
undefined

GET - 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
undefined
401 Unauthorized # 未认证 403 Forbidden # 已认证但无权限 409 Conflict # 资源状态冲突 422 Unprocessable # 验证失败 429 Too Many Requests # 请求超限 500 Internal Error # 服务器错误 503 Service Unavailable # 维护/过载
undefined

Error 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

过滤与排序

undefined
undefined

✅ 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
undefined
GET /users?q=john GET /users?search=john@example
undefined

Consistent 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

版本控制

undefined
undefined

✅ 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
undefined
GET /api/users?version=2
undefined

Rate Limiting

请求频率限制

undefined
undefined

✅ 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 } }
undefined
HTTP/1.1 429 Too Many Requests Retry-After: 60
{ "error": { "code": "RATE_LIMITED", "message": "请求过于频繁,请60秒后重试。", "retry_after": 60 } }
undefined

Actions on Resources

资源操作

undefined
undefined

For 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
undefined
POST /auth/login POST /auth/logout POST /auth/refresh POST /password/reset POST /password/reset/confirm
undefined

Request 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 issue
Example:
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