7.5 KiB
第5-5课:RESTful API设计
一、本课目标
完成本课后,你能够:
- 理解资源、资源标识和资源表现形式;
- 解释表述性状态转移(Representational State Transfer,REST)的基本思想;
- 使用路径、HTTP方法和状态码共同描述一个接口;
- 区分列表接口、详情接口和业务动作接口;
- 为图书管理系统设计一组结构一致的RESTful API。
二、前置知识
- 已学过URL和HTTP请求方法;
- 已学过HTTP响应和常用状态码;
- 已学过JSON请求体和响应体;
- 不要求接触过FastAPI、Django或任何接口框架。
三、先理解“资源”
资源(Resource)是系统希望通过接口管理的业务对象,例如图书、作者、用户和订单。它不是只指数据库中的一行,也不是只指一个Python对象,而是从接口使用者角度看到的业务事物。
一本编号为10的图书可以用路径表示:
/books/10
这里:
books表示图书资源集合;10用于标识集合中的一本图书;- 返回的JSON是这本图书在当前时刻的一种表现形式。
同一个资源可以有JSON、HTML等不同表现形式,但后端API通常返回JSON。
四、REST与RESTful是什么
REST是一种Web接口架构风格,不是协议、框架或Python库。RESTful表示一个接口的设计遵循REST的资源化思想。
入门阶段先掌握三条核心规则:
- 路径主要描述资源,优先使用名词;
- HTTP方法描述想对资源做什么;
- HTTP状态码描述处理结果。
因此创建图书通常写成:
POST /books → 201 Created
而不是:
POST /createBook → 200 OK
后一种不一定不能运行,但它没有充分利用HTTP已有的语义。
五、从一个接口开始设计
设计接口时按以下顺序思考:
- 管理的业务资源是什么?这里是图书;
- 是操作集合还是单个资源?
/books是集合,/books/10是单个资源; - 操作意图是什么?查询、创建、修改还是删除;
- 输入放在哪里?路径参数、查询参数或JSON请求体;
- 成功返回什么状态码和数据?
- 可能失败的情况有哪些?
六、图书资源接口
| 方法 | 路径 | 输入位置 | 成功状态 | 作用 |
|---|---|---|---|---|
| GET | /books |
查询参数 | 200 | 查询图书列表 |
| GET | /books/{book_id} |
路径参数 | 200 | 查询一本图书 |
| POST | /books |
JSON请求体 | 201 | 创建图书 |
| PUT | /books/{book_id} |
JSON请求体 | 200或204 | 整体替换图书 |
| PATCH | /books/{book_id} |
JSON请求体 | 200或204 | 修改部分字段 |
| DELETE | /books/{book_id} |
路径参数 | 204 | 删除图书 |
表中的{book_id}是路径参数占位符。真实请求会写成/books/10,花括号不会原样发送。
七、列表、详情与分页
列表接口操作资源集合:
GET /books?keyword=Python&page=1&page_size=20
keyword负责筛选;page表示第几页;page_size表示每页多少条。
一种清晰的列表响应是:
{
"items": [
{"id": 10, "title": "Python入门"}
],
"page": 1,
"page_size": 20,
"total": 1
}
详情接口操作单个资源:
GET /books/10
存在时返回200和图书JSON;不存在时返回404,而不是返回200和空字符串。
八、新增接口的完整设计
请求:
POST /books HTTP/1.1
Content-Type: application/json
{"title": "Web基础", "price": 59.00}
成功响应:
HTTP/1.1 201 Created
Location: /books/10
Content-Type: application/json
{"id": 10, "title": "Web基础", "price": 59.00}
Location响应头告诉客户端新资源的地址。常见失败包括JSON格式错误、字段不合规则和图书编号冲突。
九、PUT与PATCH的区别
- PUT通常表示用请求内容整体替换资源的可修改状态;
- PATCH通常表示只修改请求中出现的字段。
例如只修改价格时,PATCH请求体可以是:
{"price": 69.00}
项目必须明确PUT缺少字段时如何处理。不要仅凭方法名称猜测,接口文档需要写清楚。
十、业务动作如何设计
不是所有业务都能自然表示为基础增删改查。例如“取消订单”是一个带业务规则的动作。
可以把取消记录理解成订单下的子资源:
POST /orders/10/cancellations
也有项目使用:
POST /orders/10/cancel
RESTful不是机械规则。选择能够清楚表达业务、便于权限与审计、并且全项目一致的方案更重要。
十一、错误响应也需要设计
同一个详情接口可能产生不同结果:
| 情况 | 状态码 | 响应含义 |
|---|---|---|
| 查询成功 | 200 | 返回资源 |
| 编号格式错误 | 400或422 | 客户端输入不符合要求 |
| 图书不存在 | 404 | 找不到指定资源 |
| 未登录 | 401 | 需要完成身份认证 |
| 没有权限 | 403 | 身份已知但禁止访问 |
| 后端未知异常 | 500 | 服务器未能完成处理 |
错误响应应保持固定结构,例如包含错误代码和面向调用者的消息,但不能泄露数据库密码或程序堆栈。
十二、完整示例
rest_api_design_example.py不建立网络连接,而是把一组接口设计保存为Python列表并输出。这样可以把注意力放在方法、路径和状态码的组合上。
十三、运行方法
cd D:\Code\Python\05_web基础\5_5_RESTful_API设计
python rest_api_design_example.py
预期输出包含五条图书接口和一个带筛选、分页参数的列表请求示例。
十四、代码执行顺序
main()调用build_book_api_design();- 函数返回由多个字典组成的列表;
print_api_design()逐条读取接口;- 每条接口按统一列顺序输出;
- 最后输出列表筛选示例。
示例中的数据结构只是“接口设计表”,不是服务器,也不会真的新增或删除图书。
十五、常见错误
15.1 路径全部使用动词
/getBooks、/createBook和/deleteBook会把HTTP方法已有的意图重复写入路径,并使接口越来越不一致。
15.2 用GET修改数据
浏览器、缓存或爬虫可能自动访问GET链接。GET应当用于读取,不能因为输入方便就用它删除数据。
15.3 列表接口一次返回全部数据
数据增长后会拖慢数据库、服务器和客户端。列表接口应尽早明确分页规则和最大每页数量。
15.4 只设计成功响应
客户端真正需要处理的往往是校验失败、资源不存在、状态冲突和权限不足。接口设计必须包含失败边界。
15.5 认为RESTful只有唯一答案
REST提供设计思想,复杂业务动作可能有多种合理表达。项目内一致、语义清楚和文档完整比形式上的绝对统一更重要。
十六、课堂练习
打开practice.py,完成作者资源、订单业务动作和反例改造练习。练习文件不含参考答案。
十七、本课小结
RESTful API围绕资源组织路径,用HTTP方法表达操作,用状态码表达结果。设计一个接口时,不仅要考虑成功路径,还要明确输入位置、错误状态和响应结构。
十八、验收标准
- 能解释资源、集合路径和详情路径;
- 能组合路径、方法和状态码;
- 能区分查询参数、路径参数和JSON请求体;
- 能解释PUT与PATCH的基本差异;
- 能设计包含失败结果的图书接口;
- 示例可独立运行;
- 完成
practice.py中的练习。