Appearance
40|RESTful API 设计规范
接口写得多了,设计问题会集中暴露:URL 命名不统一、返回结构不一致、状态码使用混乱。RESTful 是一种广泛接受的 API 设计风格,它不是强制标准,但提供了一套让接口可预测、可维护的约定。这篇整理 URL 命名、HTTP 方法语义、状态码选择和版本控制。
一、URL 命名
RESTful 的 URL 用名词复数表示资源,不用动词:
| 方法 | URL | 作用 |
|---|---|---|
| GET | /servers | 查询服务器列表 |
| GET | /servers/{id} | 查询单台服务器 |
| POST | /servers | 创建服务器 |
| PUT | /servers/{id} | 全量更新服务器 |
| PATCH | /servers/{id} | 部分更新服务器 |
| DELETE | /servers/{id} | 删除服务器 |
不要在 URL 中写动词:
不推荐:/getServers、/createServer、/deleteServer/1
推荐:/servers、/servers(POST)、/servers/1(DELETE)动作交给 HTTP 方法表达,URL 只表达资源。
嵌套资源
资源之间的从属关系用 URL 层级表达:
GET /projects/{id}/servers # 某项目下的服务器
POST /projects/{id}/servers # 在某项目下创建服务器
GET /servers/{id}/tasks # 某服务器的任务历史嵌套层级不要过深,超过三层考虑用查询参数替代:
不推荐:/projects/1/servers/2/tasks/3/logs
推荐:/tasks/3/logs搜索与过滤
GET /servers?status=running&env=prod # 过滤
GET /servers?sort=-created_at # 排序(- 表示倒序)
GET /servers?q=web # 搜索二、HTTP 方法语义
| 方法 | 幂等性 | 用途 |
|---|---|---|
| GET | 是 | 获取资源,无副作用 |
| POST | 否 | 创建资源,可能产生副作用 |
| PUT | 是 | 全量替换资源 |
| PATCH | 否(通常) | 部分更新资源 |
| DELETE | 是 | 删除资源 |
幂等性:同样的请求执行一次和执行多次,结果相同。GET、PUT、DELETE 是幂等的,POST 不是。设计接口时,幂等操作可以用重试机制保证可靠性。
PUT vs PATCH
json
// PUT:客户端必须提供资源的完整表示,缺失字段会被清空
PUT /servers/1
{
"hostname": "web-01",
"ip": "192.168.1.10",
"status": "running"
}
// PATCH:只传需要修改的字段
PATCH /servers/1
{
"status": "stopped"
}三、状态码
| 状态码 | 使用场景 |
|---|---|
| 200 OK | GET、PUT、PATCH 成功 |
| 201 Created | POST 创建成功,响应头可带 Location |
| 204 No Content | DELETE 成功,无返回体 |
| 400 Bad Request | 请求参数格式错误 |
| 401 Unauthorized | 未提供认证凭证 |
| 403 Forbidden | 凭证有效但权限不足 |
| 404 Not Found | 资源不存在 |
| 409 Conflict | 资源冲突(如重复创建) |
| 422 Unprocessable Entity | 参数校验失败(FastAPI 默认) |
| 500 Internal Server Error | 服务器内部错误 |
201 Created 的 Location 头
python
@app.post("/servers", status_code=201)
async def create_server(data: ServerCreate):
new_server = create(data)
return JSONResponse(
status_code=201,
content=new_server,
headers={"Location": f"/servers/{new_server['id']}"},
)四、版本控制
API 需要演进,但已有的客户端不能随意破坏。版本控制策略:
URL 路径版本
/api/v1/servers
/api/v2/servers最直观,但 URL 会膨胀。
请求头版本
GET /servers
Accept: application/vnd.api.v1+jsonURL 干净,但客户端需要额外配置请求头。
小型项目通常用 URL 版本,简单粗暴,不容易出错。
五、常见错误
在 URL 中写动词
POST /servers/create # 错误
POST /servers # 正确状态码使用不当
python
# 错误:资源不存在返回 400(400 是请求语法错误,不是资源缺失)
raise HTTPException(status_code=400, detail="服务器不存在")
# 正确
raise HTTPException(status_code=404, detail="服务器不存在")GET 请求有副作用
GET /servers/1/restart # 错误:GET 不应该修改状态
POST /servers/1/restart # 正确不统一的复数形式
/servers # 复数
/server/1 # 单数(不一致)
统一用复数:
/servers
/servers/1