目录
- 什么是 RESTful API?
- Python RESTful API 开发框架
- Flask
- Django REST framework (DRF)
- FastAPI
- 核心概念与最佳实践
- HTTP 方法
- URL 设计 (URI)
- 状态码
- 数据格式
- 认证与授权
- 版本控制
- 异常处理
- 完整代码示例
- 使用 Flask + Flask-RESTx
- 使用 FastAPI
- API 文档自动化
- Swagger / OpenAPI
- ReDoc
- 进阶主题
- 数据库集成
- 测试
- 部署
什么是 RESTful API?
REST (Representational State Transfer,表述性状态转移) 是一种软件架构风格,而不是一个标准,它使用 HTTP 协议来创建、读取、更新和删除资源。
RESTful API 的核心思想是将数据视为“资源”,并通过标准的 HTTP 方法对这些资源进行操作。
RESTful 的关键特征:
- 无状态: 服务器不保存客户端的状态,每个请求都包含处理该请求所需的所有信息。
- 面向资源: URL 唯一标识一个资源,
/users,/products/123。 - 使用标准 HTTP 方法:
GET: 获取资源。POST: 创建新资源。PUT: 更新整个资源(幂等)。PATCH: 部分更新资源(非幂等)。DELETE: 删除资源。
- 使用标准 HTTP 状态码:
200 OK,201 Created,404 Not Found,500 Internal Server Error。 - 数据格式: 通常使用 JSON 或 XML,JSON 是目前最主流的选择。
Python RESTful API 开发框架
Python 生态中有多个优秀的框架用于构建 RESTful API。
a. Flask
Flask 是一个轻量级的“微框架”,非常灵活,适合小型项目或作为更大应用的一部分。
- 优点: 简单、易学、高度可扩展。
- 缺点: 对于大型项目,需要自己组合很多组件(如 ORM、认证等)。
- 核心库:
Flask - 推荐扩展:
Flask-RESTx: 提供了创建 REST API 的工具,自动生成交互式 Swagger UI 文档,比Flask-RESTful更现代。Flask-SQLAlchemy: ORM,用于数据库操作。Flask-JWT-Extended: 用于处理 JWT 认证。
b. Django REST framework (DRF)
DRF 是基于 Django 框架构建的强大、灵活的工具集,它为 Django 提供了构建 RESTful API 的能力。
- 优点: 功能全面、文档完善、内置强大的序列化器、权限控制和认证系统。
- 缺点: 学习曲线较陡,对于非常简单的项目可能显得有些“重”。
- 核心库:
djangorestframework
c. FastAPI
FastAPI 是一个现代、快速的(高性能) Web 框架,用于构建 API,它基于 Python 3.6+ 的类型提示。
- 优点: 性能极高(与 Node.js 和 Go 相当)、自动生成 OpenAPI 文档、内置数据验证(使用 Pydantic)、易于学习和使用。
- 缺点: 相对较新,但社区发展非常迅速。
- 核心特性: 自动交互式 API 文档(Swagger UI 和 ReDoc)、依赖注入系统。
核心概念与最佳实践
HTTP 方法
| 方法 | 行为 | 幂等性 | 安全性 |
|---|---|---|---|
GET |
读取资源 | 是 | 是 |
POST |
创建资源 | 否 | 否 |
PUT |
替换整个资源 | 是 | 否 |
PATCH |
部分更新资源 | 否 | 否 |
DELETE |
删除资源 | 是 | 否 |
幂等性:多次执行同一操作,结果与执行一次相同。GET 和 DELETE 通常是幂等的。
URL 设计
- 使用名词复数形式表示资源集合:
/users,/products。 - 使用嵌套表示资源间的关系:
/users/123/orders(用户123的所有订单)。 - 使用查询参数进行过滤、排序和分页:
/products?category=books&sort=price&page=2。
状态码
2xx(成功):200 OK,201 Created,204 No Content(成功但无返回内容)4xx(客户端错误):400 Bad Request,401 Unauthorized,403 Forbidden,404 Not Found,405 Method Not Allowed5xx(服务器错误):500 Internal Server Error
数据格式
JSON (JavaScript Object Notation) 是事实上的标准。
请求示例 (POST):
{
"name": "John Doe",
"email": "john.doe@example.com"
}
响应示例 (GET /users/123):
{
"id": 123,
"name": "John Doe",
"email": "john.doe@example.com"
}
认证与授权
- 认证: 确认用户身份是谁,常用方法有 API Key、JWT (JSON Web Token)。
- 授权: 确认用户是否有权限执行某个操作。
版本控制
当 API 发生重大变更时,需要进行版本控制,以避免破坏现有客户端。
- URL 路径:
/api/v1/users - 查询参数:
?version=v1 - 请求头:
Accept: application/vnd.company.v1+json
完整代码示例
我们将创建一个简单的 "Todo List" API。
a. 使用 Flask + Flask-RESTx
安装依赖
pip install flask flask-restx
创建 app.py
from flask import Flask
from flask_restx import Api, Resource, fields, reqparse
app = Flask(__name__)
api = Api(app, version='1.0', title='TodoMVC API', description='A simple TodoMVC API')
# 定义命名空间,使 API 更有组织
ns = api.namespace('todos', description='Todo operations')
# 定义数据模型,用于文档生成和验证
todo_model = api.model('Todo', {
'id': fields.Integer(required=True, description='Todo task unique identifier'),
'task': fields.String(required=True, description='The task details'),
'done': fields.Boolean(required=False, description='Indicates if the task is done'),
})
# 模拟数据库
todos = {}
todo_id_counter = 1
# 请求解析器,用于验证和解析请求数据
parser = reqparse.RequestParser()
parser.add_argument('task', type=str, required=True, help='Task cannot be blank!')
@ns.route('/')
class TodoList(Resource):
@ns.marshal_list_with(todo_model) # 使用模型序列化响应
def get(self):
"""列出所有待办事项"""
return list(todos.values())
@ns.expect(parser) # 期望请求数据符合 parser 的定义
@ns.marshal_with(todo_model, code=201) # 序列化响应,并返回 201 状态码
def post(self):
"""创建一个新的待办事项"""
global todo_id_counter
args = parser.parse_args()
todo = {'id': todo_id_counter, 'task': args['task'], 'done': False}
todos[todo_id_counter] = todo
todo_id_counter += 1
return todo, 201
@ns.route('/<int:todo_id>')
@ns.response(404, 'Todo not found')
@ns.param('todo_id', 'The task identifier')
class Todo(Resource):
@ns.marshal_with(todo_model)
def get(self, todo_id):
"""获取单个待办事项"""
todo = todos.get(todo_id)
if not todo:
api.abort(404, "Todo not found")
return todo
@ns.expect(parser)
@ns.marshal_with(todo_model)
def put(self, todo_id):
"""更新一个待办事项"""
args = parser.parse_args()
todo = todos.get(todo_id)
if not todo:
api.abort(404, "Todo not found")
todo['task'] = args['task']
return todo
def delete(self, todo_id):
"""删除一个待办事项"""
if todo_id not in todos:
api.abort(404, "Todo not found")
del todos[todo_id]
return '', 204 # No Content
if __name__ == '__main__':
app.run(debug=True)
运行并访问文档
python app.py
然后打开浏览器访问 http://127.0.0.1:5000/,你会看到一个 Swagger UI 界面,可以直接测试你的 API。
b. 使用 FastAPI
安装依赖
pip install fastapi "uvicorn[standard]"
创建 main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI("TodoMVC API",
description="A simple TodoMVC API with FastAPI",
version="1.0.0"
)
# Pydantic 模型,用于数据验证和序列化
class Todo(BaseModel):
task: str
done: bool = False
# 模拟数据库
todos_db = {}
todo_id_counter = 1
@app.get("/")
def read_root():
return {"message": "Welcome to the TodoMVC API"}
@app.get("/todos", response_model=list[Todo])
def get_all_todos():
"""列出所有待办事项"""
return list(todos_db.values())
@app.post("/todos", response_model=Todo, status_code=201)
def create_todo(todo: Todo):
"""创建一个新的待办事项"""
global todo_id_counter
todo_id = todo_id_counter
todos_db[todo_id] = todo
todo_id_counter += 1
return todo
@app.get("/todos/{todo_id}", response_model=Todo)
def get_todo(todo_id: int):
"""获取单个待办事项"""
todo = todos_db.get(todo_id)
if not todo:
raise HTTPException(status_code=404, detail="Todo not found")
return todo
@app.put("/todos/{todo_id}", response_model=Todo)
def update_todo(todo_id: int, todo: Todo):
"""更新一个待办事项"""
if todo_id not in todos_db:
raise HTTPException(status_code=404, detail="Todo not found")
todos_db[todo_id] = todo
return todo
@app.delete("/todos/{todo_id}")
def delete_todo(todo_id: int):
"""删除一个待办事项"""
if todo_id not in todos_db:
raise HTTPException(status_code=404, detail="Todo not found")
del todos_db[todo_id]
return {"detail": "Todo deleted successfully"}
# 运行命令: uvicorn main:app --reload
运行并访问文档
uvicorn main:app --reload
然后打开浏览器访问 http://127.0.0.1:8000/docs,FastAPI 会自动生成一个 Swagger UI 界面,访问 http://127.0.0.1:8000/redoc 可以看到 ReDoc 风格的文档。
API 文档自动化
好的 API 必须有好的文档,现代 Python 框架极大地简化了这一过程。
- Swagger / OpenAPI: 一套用于描述 API 的规范,描述文件通常为
openapi.json或openapi.yaml。 - Swagger UI: 一个基于 OpenAPI 规范的 Web 应用,可以将 API 文档渲染成交互式的界面,允许开发者直接在浏览器中测试 API。
- ReDoc: 另一个流行的 OpenAPI 文档渲染器,界面更简洁,专注于阅读。
FastAPI 和 Flask-RESTx 的最大优势之一就是它们能根据你的代码和模型定义,自动生成 OpenAPI 规范,并附带 Swagger UI 和 ReDoc。 这意味着你的代码和文档始终保持同步。
进阶主题
数据库集成
在真实应用中,你需要连接数据库。
- SQLAlchemy: Python 最流行的 ORM,支持多种数据库(PostgreSQL, MySQL, SQLite 等)。
- Django ORM: 如果使用 Django,这是内置的 ORM。
- MongoDB: 使用
pymongo库进行连接。
示例 (使用 SQLAlchemy with Flask):
from flask_sqlalchemy import SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todos.db'
db = SQLAlchemy(app)
class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True)
task = db.Column(db.String(200), nullable=False)
done = db.Column(db.Boolean, default=False)
# 在你的视图中,不再使用模拟数据库,而是使用 db.session
# new_todo = Todo(task=args['task'])
# db.session.add(new_todo)
# db.session.commit()
测试
API 必须经过测试。
pytest: Python 最流行的测试框架。requests: 用于向你的 API 发送 HTTP 请求进行测试。httpx: 一个现代的、异步的 HTTP 客户端,是requests的一个很好的替代品。
示例 (使用 pytest 和 requests 测试 FastAPI):
# test_main.py
import pytest
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_create_todo():
response = client.post("/todos", json={"task": "Test a new todo"})
assert response.status_code == 201
assert response.json()["task"] == "Test a new todo"
def test_get_todos():
# 先创建一个
client.post("/todos", json={"task": "Get all todos test"})
# 再获取所有
response = client.get("/todos")
assert response.status_code == 200
assert len(response.json()) > 0
部署
开发完成后,你需要将 API 部署到服务器上。
- ASGI 服务器: 用于运行异步应用(如 FastAPI)或兼容 ASGI 的 WSGI 应用。
- Uvicorn: 轻量级,适合开发和生产。
- Gunicorn: 更传统的 WSGI 服务器,也可以配合 Uvicorn 运行 ASGI 应用。
- 容器化: 使用 Docker 将你的应用及其依赖打包成一个容器,实现环境一致性和易于部署。
- 云平台: 将容器部署到云服务上,如 AWS, Google Cloud, Azure,它们提供了负载均衡、自动扩展等强大功能。
| 特性 | Flask + Flask-RESTx | Django REST framework | FastAPI |
|---|---|---|---|
| 易用性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 性能 | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 文档生成 | ⭐⭐⭐⭐⭐ (自动 Swagger) | ⭐⭐⭐⭐⭐ (自动 OpenAPI) | ⭐⭐⭐⭐⭐ (自动 Swagger/ReDoc) |
| 功能丰富度 | ⭐⭐⭐ (需扩展) | ⭐⭐⭐⭐⭐ (内置丰富功能) | ⭐⭐⭐⭐ (核心功能强大,依赖第三方) |
| 学习曲线 | 平缓 | 较陡 | 平缓 |
如何选择?
- 初学者 / 小型项目 / 微服务: Flask 或 FastAPI 都是绝佳选择,FastAPI 的性能和现代特性尤其吸引人。
- 大型项目 / 基于 Django 的项目: Django REST framework 是不二之选,它提供了企业级所需的一切。
- 追求极致性能 / 现代化 API: FastAPI 是首选,其异步支持和自动数据验证/文档生成非常强大。
希望这份全面的指南能帮助你开始在 Python 世界中构建 RESTful API!
