api-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

API Best Practices

API最佳实践

This skill provides comprehensive guidance for designing, implementing, and documenting RESTful APIs following industry best practices.
本技能提供遵循行业最佳实践的RESTful API设计、实现和文档编写的全面指导。

RESTful Design Principles

RESTful设计原则

Resource-Oriented Design

面向资源的设计

APIs should be designed around resources (nouns), not actions (verbs):
Good:
http
GET    /api/v1/users
POST   /api/v1/users
GET    /api/v1/users/{id}
PUT    /api/v1/users/{id}
DELETE /api/v1/users/{id}
Bad:
http
GET    /api/v1/getUsers
POST   /api/v1/createUser
POST   /api/v1/updateUser
POST   /api/v1/deleteUser
API应围绕资源(名词)而非操作(动词)进行设计:
推荐写法:
http
GET    /api/v1/users
POST   /api/v1/users
GET    /api/v1/users/{id}
PUT    /api/v1/users/{id}
DELETE /api/v1/users/{id}
不推荐写法:
http
GET    /api/v1/getUsers
POST   /api/v1/createUser
POST   /api/v1/updateUser
POST   /api/v1/deleteUser

HTTP Methods and Their Meanings

HTTP方法及其含义

  • GET: Retrieve a resource (safe, idempotent, cacheable)
  • POST: Create a new resource (not idempotent)
  • PUT: Replace entire resource (idempotent)
  • PATCH: Partial update (not necessarily idempotent)
  • DELETE: Remove a resource (idempotent)
  • GET: 获取资源(安全、幂等、可缓存)
  • POST: 创建新资源(非幂等)
  • PUT: 替换整个资源(幂等)
  • PATCH: 部分更新(不一定幂等)
  • DELETE: 删除资源(幂等)

HTTP Status Codes

HTTP状态码

Success (2xx):
  • 200 OK
    : Successful GET, PUT, PATCH, DELETE
  • 201 Created
    : Successful POST with resource creation
  • 202 Accepted
    : Request accepted for async processing
  • 204 No Content
    : Successful DELETE or update with no response body
Client Errors (4xx):
  • 400 Bad Request
    : Malformed request, validation error
  • 401 Unauthorized
    : Authentication required
  • 403 Forbidden
    : Authenticated but not authorized
  • 404 Not Found
    : Resource doesn't exist
  • 409 Conflict
    : Resource conflict (duplicate, version mismatch)
  • 422 Unprocessable Entity
    : Valid syntax but semantic errors
  • 429 Too Many Requests
    : Rate limit exceeded
Server Errors (5xx):
  • 500 Internal Server Error
    : Unexpected server error
  • 502 Bad Gateway
    : Upstream service failure
  • 503 Service Unavailable
    : Temporary overload or maintenance
  • 504 Gateway Timeout
    : Upstream timeout
成功状态(2xx):
  • 200 OK
    : GET、PUT、PATCH、DELETE请求成功
  • 201 Created
    : POST请求成功且创建了资源
  • 202 Accepted
    : 请求已接受,将异步处理
  • 204 No Content
    : DELETE或更新请求成功,无响应体
客户端错误(4xx):
  • 400 Bad Request
    : 请求格式错误、验证失败
  • 401 Unauthorized
    : 需要身份验证
  • 403 Forbidden
    : 已通过身份验证,但无权限
  • 404 Not Found
    : 资源不存在
  • 409 Conflict
    : 资源冲突(重复、版本不匹配)
  • 422 Unprocessable Entity
    : 请求语法合法但语义错误
  • 429 Too Many Requests
    : 请求次数超出限制
服务器错误(5xx):
  • 500 Internal Server Error
    : 服务器意外错误
  • 502 Bad Gateway
    : 上游服务故障
  • 503 Service Unavailable
    : 服务器临时过载或维护中
  • 504 Gateway Timeout
    : 上游服务超时

API Versioning

API版本控制

URL Versioning (Recommended)

URL版本控制(推荐)

http
GET /api/v1/users
GET /api/v2/users
Pros: Clear, easy to route, visible in logs Cons: Duplicate code across versions
http
GET /api/v1/users
GET /api/v2/users
优点: 清晰、易于路由、日志中可见 缺点: 不同版本间存在代码重复

Header Versioning

请求头版本控制

http
GET /api/users
Accept: application/vnd.myapi.v1+json
Pros: Clean URLs Cons: Harder to test, less visible
http
GET /api/users
Accept: application/vnd.myapi.v1+json
优点: URL更简洁 缺点: 测试难度大、可见性低

Version Management Rules

版本管理规则

  1. Never break backwards compatibility in same version
  2. Deprecate old versions with advance notice (6-12 months)
  3. Document migration guides between versions
  4. Support at least 2 major versions simultaneously
  1. 同一版本内绝不能破坏向后兼容性
  2. 提前6-12个月通知后再弃用旧版本
  3. 编写版本间的迁移指南
  4. 同时支持至少2个主要版本

Request/Response Patterns

请求/响应模式

Standard Request Format

标准请求格式

JSON Request Body:
json
{
  "email": "user@example.com",
  "name": "John Doe",
  "preferences": {
    "newsletter": true,
    "notifications": false
  }
}
Query Parameters (for filtering, pagination, sorting):
http
GET /api/v1/users?role=admin&status=active&page=2&limit=20&sort=-created_at
JSON请求体:
json
{
  "email": "user@example.com",
  "name": "John Doe",
  "preferences": {
    "newsletter": true,
    "notifications": false
  }
}
查询参数(用于过滤、分页、排序):
http
GET /api/v1/users?role=admin&status=active&page=2&limit=20&sort=-created_at

Standard Response Format

标准响应格式

Success Response:
json
{
  "data": {
    "id": "user_123",
    "email": "user@example.com",
    "name": "John Doe",
    "createdAt": "2025-10-16T10:30:00Z"
  }
}
Error Response:
json
{
  "error": {
    "code": "INVALID_EMAIL",
    "message": "Email address is invalid",
    "field": "email",
    "details": "Email must contain @ symbol"
  }
}
Collection Response with Pagination:
json
{
  "data": [
    { "id": 1, "name": "User 1" },
    { "id": 2, "name": "User 2" }
  ],
  "pagination": {
    "page": 2,
    "limit": 20,
    "total": 156,
    "totalPages": 8,
    "hasNext": true,
    "hasPrev": true
  },
  "links": {
    "self": "/api/v1/users?page=2",
    "next": "/api/v1/users?page=3",
    "prev": "/api/v1/users?page=1",
    "first": "/api/v1/users?page=1",
    "last": "/api/v1/users?page=8"
  }
}
成功响应:
json
{
  "data": {
    "id": "user_123",
    "email": "user@example.com",
    "name": "John Doe",
    "createdAt": "2025-10-16T10:30:00Z"
  }
}
错误响应:
json
{
  "error": {
    "code": "INVALID_EMAIL",
    "message": "邮箱地址无效",
    "field": "email",
    "details": "邮箱必须包含@符号"
  }
}
带分页的集合响应:
json
{
  "data": [
    { "id": 1, "name": "User 1" },
    { "id": 2, "name": "User 2" }
  ],
  "pagination": {
    "page": 2,
    "limit": 20,
    "total": 156,
    "totalPages": 8,
    "hasNext": true,
    "hasPrev": true
  },
  "links": {
    "self": "/api/v1/users?page=2",
    "next": "/api/v1/users?page=3",
    "prev": "/api/v1/users?page=1",
    "first": "/api/v1/users?page=1",
    "last": "/api/v1/users?page=8"
  }
}

Authentication Patterns

身份验证模式

JWT (JSON Web Tokens)

JWT(JSON Web Tokens)

Login Flow:
http
POST /api/v1/auth/login
{
  "email": "user@example.com",
  "password": "SecurePassword123"
}

Response (200):
{
  "accessToken": "eyJhbGc...",
  "refreshToken": "eyJhbGc...",
  "expiresIn": 900
}
Using Access Token:
http
GET /api/v1/users/me
Authorization: Bearer eyJhbGc...
Token Refresh:
http
POST /api/v1/auth/refresh
{
  "refreshToken": "eyJhbGc..."
}

Response (200):
{
  "accessToken": "eyJhbGc...",
  "expiresIn": 900
}
登录流程:
http
POST /api/v1/auth/login
{
  "email": "user@example.com",
  "password": "SecurePassword123"
}

响应(200):
{
  "accessToken": "eyJhbGc...",
  "refreshToken": "eyJhbGc...",
  "expiresIn": 900
}
使用访问令牌:
http
GET /api/v1/users/me
Authorization: Bearer eyJhbGc...
令牌刷新:
http
POST /api/v1/auth/refresh
{
  "refreshToken": "eyJhbGc..."
}

响应(200):
{
  "accessToken": "eyJhbGc...",
  "expiresIn": 900
}

API Keys

API密钥

Header-based (recommended):
http
GET /api/v1/data
X-API-Key: sk_live_abc123xyz
Query parameter (less secure, use only for public data):
http
GET /api/v1/public-data?api_key=sk_live_abc123xyz
基于请求头(推荐):
http
GET /api/v1/data
X-API-Key: sk_live_abc123xyz
查询参数(安全性较低,仅用于公开数据):
http
GET /api/v1/public-data?api_key=sk_live_abc123xyz

OAuth 2.0 Flows

OAuth 2.0流程

Authorization Code Flow (for web apps):
  1. Redirect to
    /oauth/authorize
  2. User grants permission
  3. Receive authorization code
  4. Exchange code for access token at
    /oauth/token
  5. Use access token for API requests
Client Credentials Flow (for server-to-server):
http
POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=abc&client_secret=xyz
授权码流程(适用于Web应用):
  1. 重定向到
    /oauth/authorize
  2. 用户授予权限
  3. 接收授权码
  4. /oauth/token
    处用授权码换取访问令牌
  5. 使用访问令牌发起API请求
客户端凭证流程(适用于服务器到服务器):
http
POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=abc&client_secret=xyz

Error Handling

错误处理

Validation Errors

验证错误

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "errors": [
      {
        "field": "email",
        "message": "Email is required"
      },
      {
        "field": "age",
        "message": "Age must be at least 18"
      }
    ]
  }
}
json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "请求验证失败",
    "errors": [
      {
        "field": "email",
        "message": "邮箱为必填项"
      },
      {
        "field": "age",
        "message": "年龄必须至少为18岁"
      }
    ]
  }
}

Business Logic Errors

业务逻辑错误

json
{
  "error": {
    "code": "INSUFFICIENT_FUNDS",
    "message": "Account balance too low for this transaction",
    "details": {
      "balance": 50.00,
      "required": 100.00,
      "currency": "USD"
    }
  }
}
json
{
  "error": {
    "code": "INSUFFICIENT_FUNDS",
    "message": "账户余额不足以完成此交易",
    "details": {
      "balance": 50.00,
      "required": 100.00,
      "currency": "USD"
    }
  }
}

Rate Limiting Errors

请求频率限制错误

http
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1634400000
Retry-After: 3600

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "API rate limit exceeded",
    "retryAfter": 3600
  }
}
http
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1634400000
Retry-After: 3600

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "API请求频率超出限制",
    "retryAfter": 3600
  }
}

Pagination Strategies

分页策略

Offset Pagination (Simple)

偏移量分页(简单型)

http
GET /api/v1/users?offset=40&limit=20
Pros: Simple, allows jumping to any page Cons: Performance degrades with large offsets, inconsistent if data changes
http
GET /api/v1/users?offset=40&limit=20
优点: 实现简单,允许跳转到任意页面 缺点: 偏移量较大时性能下降,数据变更时结果不一致

Cursor Pagination (Recommended for large datasets)

游标分页(推荐用于大数据集)

http
GET /api/v1/users?cursor=eyJpZCI6MTIzfQ&limit=20

Response:
{
  "data": [...],
  "pagination": {
    "nextCursor": "eyJpZCI6MTQzfQ",
    "hasMore": true
  }
}
Pros: Consistent results, performant at any scale Cons: Can't jump to specific page
http
GET /api/v1/users?cursor=eyJpZCI6MTIzfQ&limit=20

响应:
{
  "data": [...],
  "pagination": {
    "nextCursor": "eyJpZCI6MTQzfQ",
    "hasMore": true
  }
}
优点: 结果一致,任意规模下性能稳定 缺点: 无法跳转到指定页面

Page-Number Pagination (User-friendly)

页码分页(用户友好型)

http
GET /api/v1/users?page=3&limit=20
Pros: User-friendly, easy to understand Cons: Same issues as offset pagination
http
GET /api/v1/users?page=3&limit=20
优点: 用户友好,易于理解 缺点: 存在与偏移量分页相同的问题

Rate Limiting

请求频率限制

Implementation Pattern

实现模式

Headers to include:
http
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1634400000
Tiered Limits:
  • Anonymous: 100 requests/hour
  • Basic tier: 1,000 requests/hour
  • Pro tier: 10,000 requests/hour
  • Enterprise: Custom limits
需包含的响应头:
http
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1634400000
分层限制:
  • 匿名用户: 100次请求/小时
  • 基础版用户: 1000次请求/小时
  • 专业版用户: 10000次请求/小时
  • 企业版用户: 自定义限制

Rate Limiting Algorithms

请求频率限制算法

Token Bucket (recommended):
  • Allows bursts
  • Smooth long-term rate
  • Most flexible
Fixed Window:
  • Simple to implement
  • Can allow double limit at window boundaries
  • Less flexible
Sliding Window:
  • More accurate than fixed window
  • More complex to implement
  • Better user experience
令牌桶算法(推荐):
  • 允许突发请求
  • 长期请求速率平稳
  • 灵活性最高
固定窗口算法:
  • 实现简单
  • 窗口边界处可能允许双倍请求量
  • 灵活性较低
滑动窗口算法:
  • 比固定窗口算法更精准
  • 实现复杂度更高
  • 用户体验更好

API Security Best Practices

API安全最佳实践

1. Always Use HTTPS

1. 始终使用HTTPS

Never send sensitive data over HTTP. Enforce HTTPS at the load balancer level.
绝不要通过HTTP传输敏感数据。在负载均衡器层面强制使用HTTPS。

2. Validate All Inputs

2. 验证所有输入

python
from pydantic import BaseModel, EmailStr, constr

class UserCreate(BaseModel):
    email: EmailStr
    password: constr(min_length=8, max_length=100)
    name: constr(min_length=1, max_length=100)
python
from pydantic import BaseModel, EmailStr, constr

class UserCreate(BaseModel):
    email: EmailStr
    password: constr(min_length=8, max_length=100)
    name: constr(min_length=1, max_length=100)

3. Sanitize Outputs

3. 清理输出

Prevent injection attacks by escaping output:
python
import html
safe_output = html.escape(user_input)
通过转义输出防止注入攻击:
python
import html
safe_output = html.escape(user_input)

4. Use Parameterized Queries

4. 使用参数化查询

python
undefined
python
undefined

✅ SAFE - Parameterized

✅ 安全 - 参数化查询

cursor.execute("SELECT * FROM users WHERE email = ?", (email,))
cursor.execute("SELECT * FROM users WHERE email = ?", (email,))

❌ UNSAFE - String concatenation

❌ 不安全 - 字符串拼接

cursor.execute(f"SELECT * FROM users WHERE email = '{email}'")
undefined
cursor.execute(f"SELECT * FROM users WHERE email = '{email}'")
undefined

5. Implement CORS Properly

5. 正确实现CORS

python
undefined
python
undefined

Be specific with origins

明确指定允许的源

CORS(app, origins=["https://myapp.com", "https://app.myapp.com"])
CORS(app, origins=["https://myapp.com", "https://app.myapp.com"])

❌ NEVER use wildcard in production

❌ 生产环境绝不要使用通配符

CORS(app, origins=["*"]) # DANGEROUS

CORS(app, origins=["*"]) # 危险

undefined
undefined

6. Authenticate Before Authorization

6. 先身份验证后授权

python
undefined
python
undefined

1. Verify JWT token (authentication)

1. 验证JWT令牌(身份验证)

2. Check user permissions (authorization)

2. 检查用户权限(授权)

3. Process request

3. 处理请求

undefined
undefined

7. Log Security Events

7. 记录安全事件

python
logger.warning(f"Failed login attempt for {email} from {ip_address}")
logger.critical(f"Privilege escalation attempt by user {user_id}")
python
logger.warning(f"来自{ip_address}{email}登录尝试失败")
logger.critical(f"用户{user_id}尝试提升权限")

8. Rate Limit Authentication Endpoints

8. 对身份验证端点做频率限制

Prevent brute force attacks:
  • /auth/login
    : 5 attempts per 15 minutes per IP
  • /auth/register
    : 3 attempts per hour per IP
  • /auth/reset-password
    : 3 attempts per hour per email
防止暴力破解攻击:
  • /auth/login
    : 每IP每15分钟最多5次尝试
  • /auth/register
    : 每IP每小时最多3次尝试
  • /auth/reset-password
    : 每邮箱每小时最多3次尝试

OpenAPI/Swagger Documentation

OpenAPI/Swagger文档

OpenAPI 3.0 Example

OpenAPI 3.0示例

yaml
openapi: 3.0.0
info:
  title: My API
  version: 1.0.0
  description: API for managing users and posts

servers:
  - url: https://api.example.com/v1
    description: Production server
  - url: https://staging-api.example.com/v1
    description: Staging server

paths:
  /users:
    get:
      summary: List users
      operationId: listUsers
      tags:
        - Users
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
    post:
      summary: Create user
      operationId: createUser
      tags:
        - Users
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreate'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  schemas:
    User:
      type: object
      required:
        - id
        - email
        - name
      properties:
        id:
          type: string
          example: user_123
        email:
          type: string
          format: email
          example: user@example.com
        name:
          type: string
          example: John Doe
        createdAt:
          type: string
          format: date-time
          example: 2025-10-16T10:30:00Z

    UserCreate:
      type: object
      required:
        - email
        - password
        - name
      properties:
        email:
          type: string
          format: email
        password:
          type: string
          minLength: 8
          maxLength: 100
        name:
          type: string
          minLength: 1
          maxLength: 100

    Pagination:
      type: object
      properties:
        page:
          type: integer
        limit:
          type: integer
        total:
          type: integer
        totalPages:
          type: integer
        hasNext:
          type: boolean
        hasPrev:
          type: boolean

    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
            details:
              type: object

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - BearerAuth: []
yaml
openapi: 3.0.0
info:
  title: My API
  version: 1.0.0
  description: API for managing users and posts

servers:
  - url: https://api.example.com/v1
    description: Production server
  - url: https://staging-api.example.com/v1
    description: Staging server

paths:
  /users:
    get:
      summary: List users
      operationId: listUsers
      tags:
        - Users
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
    post:
      summary: Create user
      operationId: createUser
      tags:
        - Users
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreate'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  schemas:
    User:
      type: object
      required:
        - id
        - email
        - name
      properties:
        id:
          type: string
          example: user_123
        email:
          type: string
          format: email
          example: user@example.com
        name:
          type: string
          example: John Doe
        createdAt:
          type: string
          format: date-time
          example: 2025-10-16T10:30:00Z

    UserCreate:
      type: object
      required:
        - email
        - password
        - name
      properties:
        email:
          type: string
          format: email
        password:
          type: string
          minLength: 8
          maxLength: 100
        name:
          type: string
          minLength: 1
          maxLength: 100

    Pagination:
      type: object
      properties:
        page:
          type: integer
        limit:
          type: integer
        total:
          type: integer
        totalPages:
          type: integer
        hasNext:
          type: boolean
        hasPrev:
          type: boolean

    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
            details:
              type: object

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - BearerAuth: []

API Endpoint Design Patterns

API端点设计模式

Collection and Resource Endpoints

集合与资源端点

http
undefined
http
undefined

Collection operations

集合操作

GET /api/v1/posts # List posts POST /api/v1/posts # Create post GET /api/v1/posts/{id} # Get specific post PUT /api/v1/posts/{id} # Replace post PATCH /api/v1/posts/{id} # Update post DELETE /api/v1/posts/{id} # Delete post
GET /api/v1/posts # 列出文章 POST /api/v1/posts # 创建文章 GET /api/v1/posts/{id} # 获取指定文章 PUT /api/v1/posts/{id} # 替换文章 PATCH /api/v1/posts/{id} # 更新文章 DELETE /api/v1/posts/{id} # 删除文章

Nested resources

嵌套资源

GET /api/v1/posts/{id}/comments # List comments for post POST /api/v1/posts/{id}/comments # Create comment on post GET /api/v1/comments/{id} # Get specific comment DELETE /api/v1/comments/{id} # Delete comment
undefined
GET /api/v1/posts/{id}/comments # 列出文章的评论 POST /api/v1/posts/{id}/comments # 在文章下创建评论 GET /api/v1/comments/{id} # 获取指定评论 DELETE /api/v1/comments/{id} # 删除评论
undefined

Action Endpoints (When REST Isn't Enough)

动作端点(当REST模式不适用时)

Sometimes you need RPC-style endpoints for actions:
http
POST /api/v1/users/{id}/verify-email
POST /api/v1/orders/{id}/cancel
POST /api/v1/posts/{id}/publish
POST /api/v1/invoices/{id}/send
Pattern:
POST /{resource}/{id}/{action}
Use when:
  • Action doesn't fit CRUD model
  • State transitions need to be explicit
  • Business logic requires specific endpoint
有时你需要RPC风格的端点来处理动作:
http
POST /api/v1/users/{id}/verify-email
POST /api/v1/orders/{id}/cancel
POST /api/v1/posts/{id}/publish
POST /api/v1/invoices/{id}/send
模式:
POST /{resource}/{id}/{action}
适用场景:
  • 动作不符合CRUD模型
  • 需要明确的状态转换
  • 业务逻辑需要特定端点

Request Validation

请求验证

Input Validation Pattern

输入验证模式

python
from pydantic import BaseModel, EmailStr, Field, validator

class UserCreate(BaseModel):
    email: EmailStr
    password: str = Field(min_length=8, max_length=100)
    name: str = Field(min_length=1, max_length=100)
    age: int = Field(ge=18, le=120)

    @validator('password')
    def password_strength(cls, v):
        if not any(c.isupper() for c in v):
            raise ValueError('Password must contain uppercase letter')
        if not any(c.isdigit() for c in v):
            raise ValueError('Password must contain digit')
        return v
python
from pydantic import BaseModel, EmailStr, Field, validator

class UserCreate(BaseModel):
    email: EmailStr
    password: str = Field(min_length=8, max_length=100)
    name: str = Field(min_length=1, max_length=100)
    age: int = Field(ge=18, le=120)

    @validator('password')
    def password_strength(cls, v):
        if not any(c.isupper() for c in v):
            raise ValueError('Password must contain uppercase letter')
        if not any(c.isdigit() for c in v):
            raise ValueError('Password must contain digit')
        return v

Validation Error Response

验证错误响应

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "errors": [
      {
        "field": "email",
        "message": "Email is required",
        "code": "REQUIRED_FIELD"
      },
      {
        "field": "password",
        "message": "Password must contain uppercase letter",
        "code": "INVALID_FORMAT"
      }
    ]
  }
}
json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "请求验证失败",
    "errors": [
      {
        "field": "email",
        "message": "邮箱为必填项",
        "code": "REQUIRED_FIELD"
      },
      {
        "field": "password",
        "message": "密码必须包含大写字母",
        "code": "INVALID_FORMAT"
      }
    ]
  }
}

Filtering, Sorting, Searching

过滤、排序、搜索

Filtering

过滤

http
undefined
http
undefined

Single filter

单一过滤条件

GET /api/v1/posts?status=published
GET /api/v1/posts?status=published

Multiple filters (AND)

多个过滤条件(逻辑与)

GET /api/v1/posts?status=published&author=john
GET /api/v1/posts?status=published&author=john

Multiple values (OR)

多值过滤(逻辑或)

GET /api/v1/posts?tags=tech,ai,ml
GET /api/v1/posts?tags=tech,ai,ml

Range filters

范围过滤

GET /api/v1/posts?created_after=2025-01-01&created_before=2025-12-31
undefined
GET /api/v1/posts?created_after=2025-01-01&created_before=2025-12-31
undefined

Sorting

排序

http
undefined
http
undefined

Single field ascending

单字段升序

GET /api/v1/posts?sort=created_at
GET /api/v1/posts?sort=created_at

Single field descending

单字段降序

GET /api/v1/posts?sort=-created_at
GET /api/v1/posts?sort=-created_at

Multiple fields

多字段排序

GET /api/v1/posts?sort=-priority,created_at
undefined
GET /api/v1/posts?sort=-priority,created_at
undefined

Searching

搜索

http
undefined
http
undefined

Full-text search

全文搜索

GET /api/v1/posts?q=machine+learning
GET /api/v1/posts?q=machine+learning

Field-specific search

字段特定搜索

GET /api/v1/posts?title=contains:machine&author=starts_with:john
undefined
GET /api/v1/posts?title=contains:machine&author=starts_with:john
undefined

Idempotency

幂等性

Idempotent Operations (Safe to Retry)

幂等操作(可安全重试)

  • GET, PUT, DELETE: Always idempotent
  • POST: Not idempotent by default
  • GET、PUT、DELETE: 始终是幂等的
  • POST: 默认非幂等

Idempotency Keys for POST

POST请求的幂等键

http
POST /api/v1/payments
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

{
  "amount": 100.00,
  "currency": "USD",
  "description": "Payment for order #123"
}
Server stores idempotency key:
  • First request: Process and return 201
  • Duplicate requests with same key: Return cached 201 response
  • Different request with same key: Return 409 Conflict
http
POST /api/v1/payments
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

{
  "amount": 100.00,
  "currency": "USD",
  "description": "Payment for order #123"
}
服务器存储幂等键:
  • 首次请求: 处理并返回201
  • 使用相同键的重复请求: 返回缓存的201响应
  • 使用相同键但请求内容不同: 返回409 Conflict

Async Operations

异步操作

Long-Running Tasks

长时间运行任务

http
POST /api/v1/reports/generate
{
  "type": "annual_summary",
  "year": 2025
}

Response (202 Accepted):
{
  "id": "job_abc123",
  "status": "processing",
  "statusUrl": "/api/v1/jobs/job_abc123"
}
http
POST /api/v1/reports/generate
{
  "type": "annual_summary",
  "year": 2025
}

响应(202 Accepted):
{
  "id": "job_abc123",
  "status": "processing",
  "statusUrl": "/api/v1/jobs/job_abc123"
}

Check Status

检查状态

http
GET /api/v1/jobs/job_abc123

Response:
{
  "id": "job_abc123",
  "status": "completed",
  "result": {
    "reportUrl": "/api/v1/reports/annual_summary_2025.pdf"
  },
  "createdAt": "2025-10-16T10:00:00Z",
  "completedAt": "2025-10-16T10:05:00Z"
}
Status values:
queued
,
processing
,
completed
,
failed
http
GET /api/v1/jobs/job_abc123

响应:
{
  "id": "job_abc123",
  "status": "completed",
  "result": {
    "reportUrl": "/api/v1/reports/annual_summary_2025.pdf"
  },
  "createdAt": "2025-10-16T10:00:00Z",
  "completedAt": "2025-10-16T10:05:00Z"
}
状态值:
queued
,
processing
,
completed
,
failed

Webhooks

Webhook

Webhook Payload

Webhook负载

json
{
  "event": "user.created",
  "timestamp": "2025-10-16T10:30:00Z",
  "id": "evt_abc123",
  "data": {
    "id": "user_123",
    "email": "user@example.com",
    "name": "John Doe"
  }
}
json
{
  "event": "user.created",
  "timestamp": "2025-10-16T10:30:00Z",
  "id": "evt_abc123",
  "data": {
    "id": "user_123",
    "email": "user@example.com",
    "name": "John Doe"
  }
}

Webhook Security

Webhook安全

HMAC Signature:
http
POST https://customer.com/webhooks
X-Webhook-Signature: sha256=abc123...
HMAC签名:
http
POST https://customer.com/webhooks
X-Webhook-Signature: sha256=abc123...

Verify signature

验证签名

import hmac import hashlib
def verify_webhook(payload, signature, secret): expected = hmac.new( secret.encode(), payload.encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(f"sha256={expected}", signature)
undefined
import hmac import hashlib
def verify_webhook(payload, signature, secret): expected = hmac.new( secret.encode(), payload.encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(f"sha256={expected}", signature)
undefined

API Performance Best Practices

API性能最佳实践

1. Use ETags for Caching

1. 使用ETag实现缓存

http
GET /api/v1/users/123
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
http
GET /api/v1/users/123
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

Client sends If-None-Match on subsequent requests

客户端后续请求时发送If-None-Match

GET /api/v1/users/123 If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Response: 304 Not Modified (if unchanged)
undefined
GET /api/v1/users/123 If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
响应: 304 Not Modified(如果资源未变更)
undefined

2. Implement Field Selection

2. 实现字段选择

http
undefined
http
undefined

Get only specific fields

仅获取特定字段

GET /api/v1/users/123?fields=id,email,name
Response: { "id": "user_123", "email": "user@example.com", "name": "John Doe" }
undefined
GET /api/v1/users/123?fields=id,email,name
响应: { "id": "user_123", "email": "user@example.com", "name": "John Doe" }
undefined

3. Use Compression

3. 使用压缩

http
Accept-Encoding: gzip, deflate
Server should compress responses >1KB.
http
Accept-Encoding: gzip, deflate
服务器应对大于1KB的响应进行压缩。

4. Batch Operations

4. 批量操作

http
undefined
http
undefined

Instead of N individual requests

替代N次单独请求

GET /api/v1/users/1 GET /api/v1/users/2 GET /api/v1/users/3
GET /api/v1/users/1 GET /api/v1/users/2 GET /api/v1/users/3

Use batch endpoint

使用批量端点

GET /api/v1/users?ids=1,2,3
undefined
GET /api/v1/users?ids=1,2,3
undefined

5. Database Query Optimization

5. 数据库查询优化

  • Use database indexes on filter fields
  • Limit result set size (max 100 items per page)
  • Use connection pooling
  • Implement query caching for expensive queries
  • 在过滤字段上创建数据库索引
  • 限制结果集大小(每页最多100条)
  • 使用连接池
  • 对复杂查询实现查询缓存

HATEOAS (Hypermedia)

HATEOAS(超媒体)

Including Links in Responses

在响应中包含链接

json
{
  "data": {
    "id": "user_123",
    "email": "user@example.com",
    "name": "John Doe"
  },
  "links": {
    "self": "/api/v1/users/123",
    "posts": "/api/v1/users/123/posts",
    "comments": "/api/v1/users/123/comments",
    "avatar": "/api/v1/users/123/avatar"
  }
}
Benefits:
  • Self-documenting API
  • Clients discover available actions
  • API evolution easier
json
{
  "data": {
    "id": "user_123",
    "email": "user@example.com",
    "name": "John Doe"
  },
  "links": {
    "self": "/api/v1/users/123",
    "posts": "/api/v1/users/123/posts",
    "comments": "/api/v1/users/123/comments",
    "avatar": "/api/v1/users/123/avatar"
  }
}
优点:
  • API自文档化
  • 客户端可发现可用操作
  • API演进更轻松

Content Negotiation

内容协商

Request Format

请求格式

http
Content-Type: application/json
Accept: application/json
http
Content-Type: application/json
Accept: application/json

Support Multiple Formats (Optional)

支持多种格式(可选)

http
undefined
http
undefined

Request JSON

请求JSON格式

Accept: application/json
Accept: application/json

Request XML

请求XML格式

Accept: application/xml
Accept: application/xml

Request CSV

请求CSV格式

Accept: text/csv
undefined
Accept: text/csv
undefined

Deprecation Strategy

弃用策略

Announce Deprecation

宣布弃用

http
GET /api/v1/old-endpoint
Sunset: Sat, 31 Dec 2025 23:59:59 GMT
Deprecation: Tue, 1 Oct 2025 00:00:00 GMT
Link: </api/v2/new-endpoint>; rel="alternate"
http
GET /api/v1/old-endpoint
Sunset: Sat, 31 Dec 2025 23:59:59 GMT
Deprecation: Tue, 1 Oct 2025 00:00:00 GMT
Link: </api/v2/new-endpoint>; rel="alternate"

Migration Guide

迁移指南

Provide clear migration path:
  1. Announce deprecation 6-12 months in advance
  2. Provide migration guide with code examples
  3. Support old and new versions simultaneously
  4. Monitor usage of deprecated endpoints
  5. Send email notifications to API consumers
  6. Finally remove deprecated endpoint
提供清晰的迁移路径:
  1. 提前6-12个月宣布弃用
  2. 提供包含代码示例的迁移指南
  3. 同时支持旧版本和新版本
  4. 监控弃用端点的使用情况
  5. 向API使用者发送邮件通知
  6. 最终移除弃用的端点

API Health and Status

API健康状态检查

Health Check Endpoint

健康检查端点

http
GET /health

Response (200):
{
  "status": "healthy",
  "version": "1.2.3",
  "timestamp": "2025-10-16T10:30:00Z"
}
http
GET /health

响应(200):
{
  "status": "healthy",
  "version": "1.2.3",
  "timestamp": "2025-10-16T10:30:00Z"
}

Readiness Check (Dependencies)

就绪检查(依赖项)

http
GET /health/ready

Response (200):
{
  "status": "ready",
  "checks": {
    "database": "ok",
    "cache": "ok",
    "messageQueue": "ok",
    "externalAPI": "ok"
  }
}

Response (503) if any dependency fails:
{
  "status": "not_ready",
  "checks": {
    "database": "ok",
    "cache": "degraded",
    "messageQueue": "failed"
  }
}
http
GET /health/ready

响应(200):
{
  "status": "ready",
  "checks": {
    "database": "ok",
    "cache": "ok",
    "messageQueue": "ok",
    "externalAPI": "ok"
  }
}

若任何依赖项失败,响应(503):
{
  "status": "not_ready",
  "checks": {
    "database": "ok",
    "cache": "degraded",
    "messageQueue": "failed"
  }
}

Testing APIs

API测试

Unit Testing Controllers

控制器单元测试

python
def test_create_user():
    response = client.post("/api/v1/users", json={
        "email": "test@example.com",
        "password": "SecurePass123",
        "name": "Test User"
    })

    assert response.status_code == 201
    assert response.json()["email"] == "test@example.com"
    assert "password" not in response.json()  # Never return passwords
python
def test_create_user():
    response = client.post("/api/v1/users", json={
        "email": "test@example.com",
        "password": "SecurePass123",
        "name": "Test User"
    })

    assert response.status_code == 201
    assert response.json()["email"] == "test@example.com"
    assert "password" not in response.json()  # 绝不要返回密码

Integration Testing

集成测试

python
def test_user_flow():
    # Create user
    response = client.post("/api/v1/users", json=user_data)
    user_id = response.json()["id"]

    # Login
    response = client.post("/api/v1/auth/login", json={
        "email": user_data["email"],
        "password": user_data["password"]
    })
    token = response.json()["accessToken"]

    # Access protected resource
    response = client.get(
        f"/api/v1/users/{user_id}",
        headers={"Authorization": f"Bearer {token}"}
    )
    assert response.status_code == 200
python
def test_user_flow():
    # 创建用户
    response = client.post("/api/v1/users", json=user_data)
    user_id = response.json()["id"]

    # 登录
    response = client.post("/api/v1/auth/login", json={
        "email": user_data["email"],
        "password": user_data["password"]
    })
    token = response.json()["accessToken"]

    # 访问受保护资源
    response = client.get(
        f"/api/v1/users/{user_id}",
        headers={"Authorization": f"Bearer {token}"}
    )
    assert response.status_code == 200

Common API Mistakes to Avoid

应避免的常见API错误

  1. Using GET for state changes: GET should be safe and idempotent
  2. Returning sensitive data: Never return passwords, tokens, secrets
  3. Inconsistent naming: Stick to camelCase or snake_case, not both
  4. Missing error details: Provide helpful error messages
  5. No rate limiting: Always implement rate limits
  6. Exposing internal IDs: Use UUIDs or slugs for public APIs
  7. No versioning: Always version from day one
  8. Ignoring CORS: Configure properly for web clients
  9. Poor pagination: Implement cursor-based for large datasets
  10. No documentation: Always provide OpenAPI docs
  1. 使用GET修改状态: GET请求应是安全且幂等的
  2. 返回敏感数据: 绝不要返回密码、令牌、密钥
  3. 命名不一致: 坚持使用驼峰式或蛇形命名,不要混用
  4. 错误信息缺失: 提供有帮助的错误提示
  5. 未做请求频率限制: 始终实现频率限制
  6. 暴露内部ID: 公开API使用UUID或别名
  7. 未做版本控制: 从第一天开始就进行版本控制
  8. 忽略CORS: 为Web客户端正确配置
  9. 分页实现不佳: 大数据集使用基于游标的分页
  10. 无文档: 始终提供OpenAPI文档

When to Use This Skill

何时使用本技能

Use this skill when:
  • Designing new API endpoints
  • Implementing REST APIs
  • Reviewing API code
  • Creating API documentation
  • Troubleshooting API issues
  • Discussing authentication/authorization
  • Planning API versioning strategy
  • Implementing rate limiting
  • Handling errors in APIs

Remember: A well-designed API is intuitive, secure, performant, and well-documented. Follow these patterns to create APIs that developers love to use.
在以下场景使用本技能:
  • 设计新的API端点
  • 实现REST API
  • 评审API代码
  • 创建API文档
  • 排查API问题
  • 讨论身份验证/授权方案
  • 规划API版本控制策略
  • 实现请求频率限制
  • 处理API中的错误

请记住: 设计良好的API应直观、安全、高性能且文档完善。遵循这些模式,打造开发者喜爱使用的API。