api-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAPI 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/deleteUserAPI应围绕资源(名词)而非操作(动词)进行设计:
推荐写法:
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/deleteUserHTTP 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):
- : Successful GET, PUT, PATCH, DELETE
200 OK - : Successful POST with resource creation
201 Created - : Request accepted for async processing
202 Accepted - : Successful DELETE or update with no response body
204 No Content
Client Errors (4xx):
- : Malformed request, validation error
400 Bad Request - : Authentication required
401 Unauthorized - : Authenticated but not authorized
403 Forbidden - : Resource doesn't exist
404 Not Found - : Resource conflict (duplicate, version mismatch)
409 Conflict - : Valid syntax but semantic errors
422 Unprocessable Entity - : Rate limit exceeded
429 Too Many Requests
Server Errors (5xx):
- : Unexpected server error
500 Internal Server Error - : Upstream service failure
502 Bad Gateway - : Temporary overload or maintenance
503 Service Unavailable - : Upstream timeout
504 Gateway Timeout
成功状态(2xx):
- : GET、PUT、PATCH、DELETE请求成功
200 OK - : POST请求成功且创建了资源
201 Created - : 请求已接受,将异步处理
202 Accepted - : DELETE或更新请求成功,无响应体
204 No Content
客户端错误(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/usersPros: 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+jsonPros: Clean URLs
Cons: Harder to test, less visible
http
GET /api/users
Accept: application/vnd.myapi.v1+json优点: URL更简洁
缺点: 测试难度大、可见性低
Version Management Rules
版本管理规则
- Never break backwards compatibility in same version
- Deprecate old versions with advance notice (6-12 months)
- Document migration guides between versions
- Support at least 2 major versions simultaneously
- 同一版本内绝不能破坏向后兼容性
- 提前6-12个月通知后再弃用旧版本
- 编写版本间的迁移指南
- 同时支持至少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_atJSON请求体:
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_atStandard 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_abc123xyzQuery 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_abc123xyzOAuth 2.0 Flows
OAuth 2.0流程
Authorization Code Flow (for web apps):
- Redirect to
/oauth/authorize - User grants permission
- Receive authorization code
- Exchange code for access token at
/oauth/token - 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应用):
- 重定向到
/oauth/authorize - 用户授予权限
- 接收授权码
- 在处用授权码换取访问令牌
/oauth/token - 使用访问令牌发起API请求
客户端凭证流程(适用于服务器到服务器):
http
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=abc&client_secret=xyzError 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=20Pros: 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=20Pros: 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: 1634400000Tiered 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
undefinedpython
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}'")
undefinedcursor.execute(f"SELECT * FROM users WHERE email = '{email}'")
undefined5. Implement CORS Properly
5. 正确实现CORS
python
undefinedpython
undefinedBe 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=["*"]) # 危险
undefinedundefined6. Authenticate Before Authorization
6. 先身份验证后授权
python
undefinedpython
undefined1. Verify JWT token (authentication)
1. 验证JWT令牌(身份验证)
2. Check user permissions (authorization)
2. 检查用户权限(授权)
3. Process request
3. 处理请求
undefinedundefined7. 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:
- : 5 attempts per 15 minutes per IP
/auth/login - : 3 attempts per hour per IP
/auth/register - : 3 attempts per hour per email
/auth/reset-password
防止暴力破解攻击:
- : 每IP每15分钟最多5次尝试
/auth/login - : 每IP每小时最多3次尝试
/auth/register - : 每邮箱每小时最多3次尝试
/auth/reset-password
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
undefinedhttp
undefinedCollection 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
undefinedGET /api/v1/posts/{id}/comments # 列出文章的评论
POST /api/v1/posts/{id}/comments # 在文章下创建评论
GET /api/v1/comments/{id} # 获取指定评论
DELETE /api/v1/comments/{id} # 删除评论
undefinedAction 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}/sendPattern:
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 vpython
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 vValidation 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
undefinedhttp
undefinedSingle 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
undefinedGET /api/v1/posts?created_after=2025-01-01&created_before=2025-12-31
undefinedSorting
排序
http
undefinedhttp
undefinedSingle 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
undefinedGET /api/v1/posts?sort=-priority,created_at
undefinedSearching
搜索
http
undefinedhttp
undefinedFull-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
undefinedGET /api/v1/posts?title=contains:machine&author=starts_with:john
undefinedIdempotency
幂等性
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: , , ,
queuedprocessingcompletedfailedhttp
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"
}状态值: , , ,
queuedprocessingcompletedfailedWebhooks
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)
undefinedimport 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)
undefinedAPI 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)
undefinedGET /api/v1/users/123
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
响应: 304 Not Modified(如果资源未变更)
undefined2. Implement Field Selection
2. 实现字段选择
http
undefinedhttp
undefinedGet only specific fields
仅获取特定字段
GET /api/v1/users/123?fields=id,email,name
Response:
{
"id": "user_123",
"email": "user@example.com",
"name": "John Doe"
}
undefinedGET /api/v1/users/123?fields=id,email,name
响应:
{
"id": "user_123",
"email": "user@example.com",
"name": "John Doe"
}
undefined3. Use Compression
3. 使用压缩
http
Accept-Encoding: gzip, deflateServer should compress responses >1KB.
http
Accept-Encoding: gzip, deflate服务器应对大于1KB的响应进行压缩。
4. Batch Operations
4. 批量操作
http
undefinedhttp
undefinedInstead 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
undefinedGET /api/v1/users?ids=1,2,3
undefined5. 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/jsonhttp
Content-Type: application/json
Accept: application/jsonSupport Multiple Formats (Optional)
支持多种格式(可选)
http
undefinedhttp
undefinedRequest JSON
请求JSON格式
Accept: application/json
Accept: application/json
Request XML
请求XML格式
Accept: application/xml
Accept: application/xml
Request CSV
请求CSV格式
Accept: text/csv
undefinedAccept: text/csv
undefinedDeprecation 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:
- Announce deprecation 6-12 months in advance
- Provide migration guide with code examples
- Support old and new versions simultaneously
- Monitor usage of deprecated endpoints
- Send email notifications to API consumers
- Finally remove deprecated endpoint
提供清晰的迁移路径:
- 提前6-12个月宣布弃用
- 提供包含代码示例的迁移指南
- 同时支持旧版本和新版本
- 监控弃用端点的使用情况
- 向API使用者发送邮件通知
- 最终移除弃用的端点
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 passwordspython
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 == 200python
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 == 200Common API Mistakes to Avoid
应避免的常见API错误
- Using GET for state changes: GET should be safe and idempotent
- Returning sensitive data: Never return passwords, tokens, secrets
- Inconsistent naming: Stick to camelCase or snake_case, not both
- Missing error details: Provide helpful error messages
- No rate limiting: Always implement rate limits
- Exposing internal IDs: Use UUIDs or slugs for public APIs
- No versioning: Always version from day one
- Ignoring CORS: Configure properly for web clients
- Poor pagination: Implement cursor-based for large datasets
- No documentation: Always provide OpenAPI docs
- 使用GET修改状态: GET请求应是安全且幂等的
- 返回敏感数据: 绝不要返回密码、令牌、密钥
- 命名不一致: 坚持使用驼峰式或蛇形命名,不要混用
- 错误信息缺失: 提供有帮助的错误提示
- 未做请求频率限制: 始终实现频率限制
- 暴露内部ID: 公开API使用UUID或别名
- 未做版本控制: 从第一天开始就进行版本控制
- 忽略CORS: 为Web客户端正确配置
- 分页实现不佳: 大数据集使用基于游标的分页
- 无文档: 始终提供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。