# REST API 设计快速参考

> 参考完整规范: `@/Python项目开发准则.md#14-api-设计规范`

## 端点命名约定

```python
from fastapi import FastAPI

app = FastAPI()

# 列表（获取所有资源）
@app.get("/api/v1/users")
async def list_users(skip: int = 0, limit: int = 100):
    """获取用户列表"""
    pass

# 创建（新建资源）
@app.post("/api/v1/users")
async def create_user(user: UserCreate):
    """创建用户"""
    pass

# 详情（获取单个资源）
@app.get("/api/v1/users/{user_id}")
async def get_user(user_id: int):
    """获取单个用户"""
    pass

# 完全更新（替换整个资源）
@app.put("/api/v1/users/{user_id}")
async def update_user(user_id: int, user: UserUpdate):
    """完全更新用户"""
    pass

# 部分更新（更新部分字段）
@app.patch("/api/v1/users/{user_id}")
async def partial_update_user(user_id: int, user: UserPartialUpdate):
    """部分更新用户"""
    pass

# 删除
@app.delete("/api/v1/users/{user_id}")
async def delete_user(user_id: int):
    """删除用户"""
    pass
```

## HTTP 状态码

```python
from fastapi import HTTPException

# 200 OK - GET/PUT/PATCH 成功
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    return user_data  # 自动返回 200

# 201 Created - POST 创建成功
@app.post("/users")
async def create_user(user: UserCreate):
    # 返回 201 + Location header
    return JSONResponse(status_code=201, content=user_data)

# 204 No Content - DELETE 成功或不返回内容
@app.delete("/users/{user_id}")
async def delete_user(user_id: int):
    return Response(status_code=204)

# 400 Bad Request - 客户端语法错误
@app.post("/users")
async def create_user(user: UserCreate):
    if not valid(user):
        raise HTTPException(status_code=400, detail="Invalid request")

# 401 Unauthorized - 需要身份验证
@app.get("/users/me", dependencies=[Depends(verify_token)])
async def get_current_user():
    pass

# 403 Forbidden - 已认证但没有权限
@app.delete("/users/{user_id}")
async def delete_user(user_id: int, current_user: User = Depends(get_current_user)):
    if not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Not authorized")

# 404 Not Found - 资源不存在
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    user = find_user(user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user

# 422 Unprocessable Entity - 验证失败（Pydantic 自动返回）
@app.post("/users")
async def create_user(user: UserCreate):  # Pydantic 验证失败时返回 422
    pass

# 429 Too Many Requests - 速率限制
@app.get("/api/data", dependencies=[Depends(rate_limit)])
async def get_data():
    pass

# 500 Internal Server Error - 服务器错误
@app.get("/users")
async def list_users():
    # 未捕获的异常返回 500
    pass
```

## 统一错误响应格式

```python
from pydantic import BaseModel
from datetime import datetime
from typing import Optional

class ErrorDetail(BaseModel):
    """单个错误详情"""
    field: str
    message: str
    code: str

class ErrorResponse(BaseModel):
    """统一的错误响应"""
    code: str  # 错误代码：VALIDATION_ERROR, NOT_FOUND 等
    message: str  # 用户友好的消息
    details: list[ErrorDetail] = []
    timestamp: str  # ISO 8601 时间

# 使用示例
error_response = ErrorResponse(
    code="VALIDATION_ERROR",
    message="Request validation failed",
    details=[
        ErrorDetail(field="email", message="Invalid email format", code="invalid_email"),
        ErrorDetail(field="age", message="Must be between 0 and 150", code="out_of_range")
    ],
    timestamp=datetime.now().isoformat()
)
```

## 请求/响应示例

### 创建用户
```bash
# 请求
POST /api/v1/users
Content-Type: application/json

{
  "name": "John Doe",
  "email": "john@example.com",
  "age": 30
}

# 成功响应 (201 Created)
{
  "id": 123,
  "name": "John Doe",
  "email": "john@example.com",
  "age": 30,
  "created_at": "2024-01-15T10:30:00Z"
}

# 验证失败 (422 Unprocessable Entity)
{
  "code": "VALIDATION_ERROR",
  "message": "Request validation failed",
  "details": [
    {
      "field": "email",
      "message": "Invalid email format",
      "code": "invalid_email"
    }
  ],
  "timestamp": "2024-01-15T10:30:00Z"
}
```

### 获取用户
```bash
# 请求
GET /api/v1/users/123

# 成功响应 (200 OK)
{
  "id": 123,
  "name": "John Doe",
  "email": "john@example.com",
  "age": 30
}

# 不存在 (404 Not Found)
{
  "code": "NOT_FOUND",
  "message": "User not found",
  "details": [],
  "timestamp": "2024-01-15T10:30:00Z"
}
```

## FastAPI 完整示例

```python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from typing import Optional

app = FastAPI(
    title="AutoReport API",
    description="自动报告生成系统",
    version="1.0.0"
)

class UserCreate(BaseModel):
    """创建用户请求"""
    name: str = Field(..., min_length=1, max_length=100)
    email: str = Field(..., pattern=r'^[\w\.-]+@[\w\.-]+\.\w+$')
    age: int = Field(..., ge=0, le=150)

class User(BaseModel):
    """用户响应"""
    id: int
    name: str
    email: str
    age: int

# 模拟数据
users_db = {}
next_id = 1

@app.post("/api/v1/users", status_code=201, response_model=User)
async def create_user(user: UserCreate):
    """创建用户"""
    global next_id
    new_user = User(id=next_id, **user.dict())
    users_db[next_id] = new_user
    next_id += 1
    return new_user

@app.get("/api/v1/users/{user_id}", response_model=User)
async def get_user(user_id: int):
    """获取单个用户"""
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="User not found")
    return users_db[user_id]

@app.get("/api/v1/users")
async def list_users(skip: int = 0, limit: int = 100):
    """获取用户列表"""
    users = list(users_db.values())
    return users[skip:skip + limit]

@app.delete("/api/v1/users/{user_id}", status_code=204)
async def delete_user(user_id: int):
    """删除用户"""
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="User not found")
    del users_db[user_id]
```

## 最佳实践

✅ **推荐：**
- 使用版本化的 URL (`/api/v1/...`)
- 返回统一的错误格式
- 使用正确的 HTTP 状态码
- 为 API 生成 OpenAPI 文档
- 实现速率限制
- 需要认证的端点添加 `Depends(verify_token)`

❌ **避免：**
- 在错误消息中泄露敏感信息
- 返回 500 错误而不记录
- 忽视 HTTP 状态码的语义含义
- API 设计不一致
- 没有文档和示例

## 参考

- [FastAPI 官方文档](https://fastapi.tiangolo.com/)
- [HTTP 状态码](https://httpwg.org/specs/rfc7231.html#status.codes)
- 完整规范：`@/Python项目开发准则.md#14-api-设计规范`
