Skip to content

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 OKGET、PUT、PATCH 成功
201 CreatedPOST 创建成功,响应头可带 Location
204 No ContentDELETE 成功,无返回体
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+json

URL 干净,但客户端需要额外配置请求头。

小型项目通常用 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