FastAPI 入门:从环境搭建到实战开发的完整指南
FastAPI 入门:从环境搭建到实战开发的完整指南
1. 引言:为什么选择 FastAPI?
在 Python Web 框架生态中,Django、Flask 早已占据半壁江山,但随着异步编程和 API 开发需求的激增,FastAPI 凭借其高性能、易用性、自动化特性迅速崛起,成为现代 API 开发的优选框架。
1.1 什么是 FastAPI?
FastAPI 是由 Sebastián Ramírez(tiangolo)开发的一款现代、高性能的 Web 框架,专为构建 API 设计。它基于 Python 3.7+ 的类型提示(Type Hints)特性,结合了 Starlette(异步 Web 框架)的高性能和 Pydantic(数据验证库)的强类型验证能力,实现了“编写代码即生成文档”“类型提示即数据验证”的便捷开发体验。
1.2 FastAPI 的核心优势
相比传统框架,FastAPI 有以下不可替代的优势:
- 极致性能:基于 Starlette 和 Uvicorn(ASGI 服务器),支持异步操作,性能接近 Node.js 和 Go,远超 Flask 等同步框架。
- 自动文档生成:无需额外配置,自动生成交互式 API 文档(Swagger UI 和 ReDoc),开发者可直接在文档中测试接口。
- 强类型验证:通过 Pydantic 和 Python 类型提示,自动校验请求参数、请求体和响应数据,减少手动验证代码。
- 极简语法:核心逻辑通过“路径操作装饰器 + 函数”实现,代码简洁易读,学习成本低。
- 异步原生支持:天然支持异步函数(
async def
),可高效处理 I/O 密集型任务(如数据库查询、API 调用)。 - 丰富的生态兼容:可与 SQLAlchemy、Pydantic、OAuth2、JWT 等主流库无缝集成,支持数据库、认证、权限控制等常见需求。
1.3 与其他框架的对比
为了更清晰地理解 FastAPI 的定位,我们将其与 Flask、Django 进行对比:
特性 | FastAPI | Flask | Django |
---|---|---|---|
性能 | 高(异步 ASGI) | 中(同步 WSGI) | 中(同步 WSGI,可扩展异步) |
自动文档 | 内置 Swagger UI/ReDoc | 需第三方库(如 Flask-RESTX) | 需第三方库(如 drf-yasg) |
数据验证 | 内置 Pydantic 验证 | 需手动或第三方库(如 Marshmallow) | 需 Django Forms/DRF Serializer |
异步支持 | 原生支持 | 需第三方库(如 Flask-AsyncExt) | 3.1+ 支持异步视图 |
学习成本 | 低(语法简洁,基于类型提示) | 低(轻量灵活) | 高(内置功能多,配置复杂) |
适用场景 | API 开发、微服务、后端接口 | 小型应用、API 原型、轻量服务 | 完整 Web 应用、内容管理系统 |
如果你的核心需求是快速构建高性能、可维护的 API,FastAPI 无疑是最优选择之一。
2. 环境搭建:从 0 到 1 准备开发环境
在开始编写代码前,我们需要先搭建符合 FastAPI 要求的开发环境。FastAPI 依赖 Python 3.7+,因此首先确保本地 Python 版本达标。
2.1 检查 Python 版本
打开终端(Windows 用命令提示符或 PowerShell,macOS/Linux 用终端),执行以下命令检查 Python 版本:
python --version # Windows
# 或
python3 --version # macOS/Linux
若输出为 Python 3.7.x
或更高版本(推荐 3.9+),则满足要求;若版本过低,需先从 Python 官网 下载并安装对应版本。
2.2 创建虚拟环境
为了避免项目依赖冲突,建议为每个 Python 项目创建独立的虚拟环境。以下是不同系统的虚拟环境创建步骤:
2.2.1 Windows 系统
- 打开命令提示符,进入你想存放项目的目录(如
D:\projects
):cd D:\projects
- 创建项目文件夹并进入:
mkdir fastapi-demo && cd fastapi-demo
- 创建虚拟环境(名称为
venv
):python -m venv venv
- 激活虚拟环境:
激活成功后,终端前缀会显示venv\Scripts\activate
(venv)
,表示当前处于虚拟环境中。
2.2.2 macOS/Linux 系统
- 打开终端,进入项目目录:
cd ~/projects # 进入用户目录下的 projects 文件夹 mkdir fastapi-demo && cd fastapi-demo
- 创建虚拟环境:
python3 -m venv venv
- 激活虚拟环境:
激活成功后,终端前缀会显示source venv/bin/activate
(venv)
。
2.3 安装核心依赖
FastAPI 的核心依赖包括 fastapi
(框架本身)和 uvicorn
(ASGI 服务器,用于运行 FastAPI 应用)。在虚拟环境中执行以下命令安装:
pip install fastapi uvicorn
若需后续开发中使用数据库、数据验证扩展等功能,可提前安装常用依赖(可选):
# Pydantic(FastAPI 已依赖,无需重复安装,此处为示例)
pip install pydantic
# SQLAlchemy(ORM 工具,用于数据库操作)
pip install sqlalchemy
# python-dotenv(加载环境变量)
pip install python-dotenv
# requests(用于测试外部 API)
pip install requests
安装完成后,可通过 pip list
查看已安装的依赖,确认 fastapi
和 uvicorn
存在。
3. 第一个 FastAPI 应用:Hello World
环境搭建完成后,我们从最经典的“Hello World”开始,感受 FastAPI 的简洁性。
3.1 编写代码
- 在
fastapi-demo
文件夹中创建一个名为main.py
的文件(FastAPI 项目通常以main.py
为入口)。 - 写入以下代码:
# main.py
from fastapi import FastAPI # 导入 FastAPI 类# 创建 FastAPI 应用实例
app = FastAPI(title="FastAPI 入门 Demo", # API 文档标题description="这是一个 FastAPI 入门级示例项目", # API 文档描述version="1.0.0" # API 版本
)# 定义路径操作:GET 请求 + 根路径(/)
@app.get("/", summary="根路径", description="返回 Hello World 消息")
def read_root():"""根路径的路径操作函数:- 接收 GET 请求- 返回 JSON 格式的消息"""return {"message": "Hello World! Welcome to FastAPI."}
3.2 代码解释
上述代码仅 10 余行,却包含了 FastAPI 的核心概念,我们逐行拆解:
- 导入 FastAPI:
from fastapi import FastAPI
导入框架的核心类,用于创建应用实例。 - 创建应用实例:
app = FastAPI(...)
创建 FastAPI 实例,括号内的参数(title
、description
、version
)用于自定义自动生成的 API 文档信息。 - 路径操作装饰器:
@app.get("/")
是 FastAPI 的核心装饰器,用于定义“路径操作”:app
:FastAPI 实例。get
:指定 HTTP 方法(此处为 GET,其他常用方法如 POST、PUT、DELETE 对应app.post
、app.put
、app.delete
)。"/"
:指定 API 的路径(即访问地址的根路径)。
- 路径操作函数:
def read_root(): ...
是装饰器下方的函数,当客户端访问GET /
时,FastAPI 会自动调用该函数:- 函数名可自定义(如
read_root
、home
等),不影响功能,但建议语义化。 - 函数返回值会被 FastAPI 自动转换为 JSON 格式(支持字典、列表、Pydantic 模型等)。
- 函数名可自定义(如
- 文档注释:函数内的
""" 注释 """
和装饰器的summary
、description
参数会被自动提取到 API 文档中,提升接口可维护性。
3.3 运行应用
在虚拟环境中,执行以下命令运行 FastAPI 应用:
uvicorn main:app --reload
命令参数解释:
main:app
:指定运行的应用入口,main
是文件名(main.py
),app
是main.py
中创建的 FastAPI 实例(app = FastAPI()
)。--reload
:开启自动重载模式,当代码修改后,服务器会自动重启(仅用于开发环境,生产环境需删除该参数,避免性能损耗)。
运行成功的标志:
终端会输出类似以下内容,说明服务器已启动:
INFO: Will watch for changes in these directories: ['D:\\projects\\fastapi-demo']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [2844] using WatchFiles
INFO: Started server process [2048]
INFO: Waiting for application startup.
INFO: Application startup complete.
3.4 访问应用与自动文档
应用运行后,我们可以通过以下方式访问:
3.4.1 访问 API 接口
打开浏览器,输入地址 http://127.0.0.1:8000
,即可看到 API 返回的 JSON 结果:
{"message":"Hello World! Welcome to FastAPI."}
也可以用 curl
命令在终端访问(适合开发者快速测试):
curl http://127.0.0.1:8000
3.4.2 访问自动生成的 API 文档
FastAPI 最强大的特性之一是自动生成文档,无需任何额外配置,我们有两种文档可选:
-
Swagger UI(交互式文档):访问
http://127.0.0.1:8000/docs
,这是一个交互式文档,支持直接在页面中测试 API:- 页面会显示 API 的路径(
/
)、HTTP 方法(GET)、描述等信息。 - 点击“Try it out”→“Execute”,即可发送请求并查看响应结果(无需 Postman 等工具)。
- 页面会显示 API 的路径(
-
ReDoc(简洁文档):访问
http://127.0.0.1:8000/redoc
,这是一个更简洁、结构化的文档,适合给非开发人员(如前端、测试)查看接口定义。
这两种文档会随着代码的修改自动更新,例如新增接口后,刷新文档页面即可看到新接口的信息,极大减少了“写代码+写文档”的重复工作。
4. 路径操作进阶:路径参数与查询参数
API 开发中,参数传递是核心需求,FastAPI 支持多种参数类型,其中最常用的是路径参数(通过 URL 路径传递)和查询参数(通过 URL 后缀 ?key=value
传递)。
4.1 路径参数:从 URL 路径中获取参数
路径参数用于标识“资源的唯一标识”,例如“获取 ID 为 5 的商品”,此时 ID 就需要通过路径参数传递。
4.1.1 基础路径参数
修改 main.py
,新增一个“获取商品”的接口:
# main.py(新增代码)
@app.get("/items/{item_id}", summary="获取单个商品", description="根据商品 ID 获取商品信息")
def read_item(item_id: int):"""根据商品 ID 获取商品信息:- **item_id**: 商品的唯一 ID(必须为整数)- 返回:包含商品 ID 和默认名称的字典"""return {"item_id": item_id, "item_name": f"Item {item_id}"}
代码解释:
- 路径参数定义:
/items/{item_id}
中,{item_id}
是路径参数的占位符,FastAPI 会自动提取 URL 中对应位置的值,并传递给函数的item_id
参数。 - 类型提示的作用:
item_id: int
中的类型提示int
并非装饰,而是 FastAPI 的“数据验证规则”:- 若客户端传递的
item_id
是整数(如http://127.0.0.1:8000/items/5
),则正常返回结果。 - 若传递的是非整数(如
http://127.0.0.1:8000/items/abc
),FastAPI 会自动返回422 Unprocessable Entity
错误,并提示“值不是有效的整数”,无需手动编写验证代码。
- 若客户端传递的
测试接口:
- 访问
http://127.0.0.1:8000/items/5
,返回:{"item_id":5,"item_name":"Item 5"}
- 访问
http://127.0.0.1:8000/items/abc
,返回 422 错误:{"detail": [{"loc": ["path", "item_id"],"msg": "value is not a valid integer","type": "type_error.integer"}] }
4.1.2 路径参数的高级验证
除了基础类型验证,FastAPI 还支持通过 Path
类对路径参数进行更精细的限制(如数值范围、字符串长度、正则表达式等)。
首先需要从 fastapi
导入 Path
:
from fastapi import FastAPI, Path # 新增 Path 导入
然后修改“获取商品”接口,添加路径参数验证:
@app.get("/items/{item_id}", summary="获取单个商品", description="根据商品 ID 获取商品信息")
def read_item(# 路径参数验证:item_id 必须是整数,且大于等于 1,小于等于 1000item_id: int = Path(..., # ... 表示该参数为必填(路径参数本身就是必填的,此处用于语法提示)ge=1, # greater than or equal:大于等于le=1000, # less than or equal:小于等于title="商品 ID", # 文档中显示的参数标题description="商品的唯一标识,范围:1~1000" # 文档中显示的参数描述)
):return {"item_id": item_id, "item_name": f"Item {item_id}"}
常用 Path
验证参数:
参数 | 作用 | 适用类型 |
---|---|---|
ge | 大于等于 | 数值(int/float) |
gt | 大于 | 数值(int/float) |
le | 小于等于 | 数值(int/float) |
lt | 小于 | 数值(int/float) |
min_length | 字符串最小长度 | 字符串(str) |
max_length | 字符串最大长度 | 字符串(str) |
regex | 正则表达式匹配 | 字符串(str) |
title | 文档中显示的参数标题 | 所有类型 |
description | 文档中显示的参数描述 | 所有类型 |
测试验证效果:
- 访问
http://127.0.0.1:8000/items/0
(小于 1),返回 422 错误,提示“确保该值大于或等于 1”。 - 访问
http://127.0.0.1:8000/items/1001
(大于 1000),返回 422 错误,提示“确保该值小于或等于 1000”。 - 访问
http://127.0.0.1:8000/items/500
(符合范围),正常返回结果。
4.2 查询参数:从 URL 后缀中获取参数
查询参数用于“过滤、分页、排序”等非标识性需求,例如“获取第 2 页的商品列表,每页 10 条”,此时页码和每页条数就通过查询参数传递。
4.2.1 基础查询参数
在 main.py
中新增“获取商品列表”的接口:
# main.py(新增代码)
@app.get("/items/", summary="获取商品列表", description="分页获取商品列表")
def read_item_list(skip: int = 0, # 跳过的商品数量,默认值 0limit: int = 10 # 每页显示的商品数量,默认值 10
):"""分页获取商品列表:- **skip**: 跳过的商品数量(默认 0,即从第 1 个商品开始)- **limit**: 每页显示的商品数量(默认 10,最大可调整)- 返回:包含分页信息和商品列表的字典"""# 模拟商品数据(实际项目中从数据库查询)items = [{"item_id": i, "item_name": f"Item {i}"} for i in range(1, 101)] # 100 个商品# 分页逻辑:从 skip 开始,取 limit 个商品result = items[skip : skip + limit]return {"pagination": {"skip": skip, "limit": limit, "total": len(items)},"items": result}
代码解释:
- 查询参数定义:函数中的
skip
和limit
参数没有在路径中定义(路径是/items/
),FastAPI 会自动将其识别为查询参数。 - 默认值的作用:
skip: int = 0
和limit: int = 10
中的默认值(0
和10
)表示:- 若客户端不传递该参数,将使用默认值(如访问
http://127.0.0.1:8000/items/
,等效于skip=0&limit=10
)。 - 若客户端传递该参数,将使用传递的值(如访问
http://127.0.0.1:8000/items/?skip=20&limit=15
)。
- 若客户端不传递该参数,将使用默认值(如访问
- 类型验证:与路径参数类似,
skip: int
和limit: int
的类型提示会自动验证参数类型,若传递非整数(如skip=abc
),会返回 422 错误。
测试接口:
- 访问
http://127.0.0.1:8000/items/
(默认参数),返回前 10 个商品:{"pagination": {"skip": 0, "limit": 10, "total": 100},"items": [{"item_id": 1, "item_name": "Item 1"}, ..., {"item_id": 10, "item_name": "Item 10"}] }
- 访问
http://127.0.0.1:8000/items/?skip=20&limit=15
(自定义参数),返回第 21~35 个商品:{"pagination": {"skip": 20, "limit": 15, "total": 100},"items": [{"item_id": 21, "item_name": "Item 21"}, ..., {"item_id": 35, "item_name": "Item 35"}] }
4.2.2 可选查询参数
若某个查询参数是“可选且无默认值”的,可使用 Python 的 Optional
类型(需从 typing
导入)。
例如,新增一个“搜索商品”的接口,支持根据名称搜索(搜索关键词是可选的):
# main.py(新增代码)
from typing import Optional # 导入 Optional 类型@app.get("/items/search/", summary="搜索商品", description="根据名称关键词搜索商品")
def search_items(q: Optional[str] = None, # 搜索关键词,可选,默认 None(表示不搜索)limit: int = 10 # 每页显示数量,默认 10
):"""搜索商品:- **q**: 搜索关键词(可选,若传递则匹配商品名称包含该关键词的商品)- **limit**: 每页显示数量(默认 10)- 返回:搜索结果列表"""# 模拟商品数据items = [{"item_id": i, "item_name": f"Item {i} - Type {i%3}"} for i in range(1, 101)]# 搜索逻辑:若 q 不为 None,筛选名称包含 q 的商品if q:items = [item for item in items if q in item["item_name"]]# 分页result = items[:limit]return {"search_query": q,"pagination": {"limit": limit, "total": len(items)},"items": result}
测试可选参数:
- 访问
http://127.0.0.1:8000/items/search/
(不传递 q),返回所有商品的前 10 个。 - 访问
http://127.0.0.1:8000/items/search/?q=Type 1
(传递 q=Type 1),返回名称包含“Type 1”的商品:{"search_query": "Type 1","pagination": {"limit": 10, "total": 34},"items": [{"item_id": 1, "item_name": "Item 1 - Type 1"}, ...] }
4.2.3 查询参数的高级验证
与路径参数类似,查询参数也可通过 Query
类进行精细验证。首先从 fastapi
导入 Query
:
from fastapi import FastAPI, Path, Query # 新增 Query 导入
修改“搜索商品”接口,添加查询参数验证:
@app.get("/items/search/", summary="搜索商品", description="根据名称关键词搜索商品")
def search_items(q: Optional[str] = Query(None, # 默认值 Nonemin_length=2, # 关键词最小长度 2(避免空字符串或单个字符)max_length=50, # 关键词最大长度 50regex="^[a-zA-Z0-9 ]+$", # 正则表达式:仅允许字母、数字和空格title="搜索关键词",description="商品名称的搜索关键词,长度 2~50,仅含字母、数字和空格"),limit: int = Query(10, # 默认值 10ge=1, # 至少显示 1 条le=50, # 最多显示 50 条(避免一次性返回过多数据)title="每页数量",description="每页显示的商品数量,范围 1~50")
):# 逻辑不变,省略...pass
测试验证效果:
- 访问
http://127.0.0.1:8000/items/search/?q=a
(关键词长度 1),返回 422 错误,提示“确保该值的长度大于或等于 2”。 - 访问
http://127.0.0.1:8000/items/search/?limit=60
(超过 50),返回 422 错误,提示“确保该值小于或等于 50”。 - 访问
http://127.0.0.1:8000/items/search/?q=Type@1
(包含特殊字符 @),返回 422 错误,提示“字符串不匹配预期的正则表达式”。
5. 请求体:处理 POST/PUT 等请求的数据
对于 POST、PUT 等 HTTP 方法,参数通常通过“请求体”(Request Body)传递(而非 URL),例如“创建商品”时,商品的名称、价格等信息需要放在请求体中。FastAPI 结合 Pydantic 模型,实现了请求体的自动解析和验证。
5.1 什么是 Pydantic?
Pydantic 是一个 Python 数据验证库,基于类型提示定义数据模型,自动校验数据类型和值的合法性。FastAPI 内置了 Pydantic,将其作为请求体和响应体的核心处理工具。
5.2 定义 Pydantic 模型
首先,我们需要定义一个 Pydantic 模型,用于描述请求体的结构(例如“创建商品”需要哪些字段)。
在 main.py
中新增以下代码:
# main.py(新增代码)
from pydantic import BaseModel # 从 Pydantic 导入 BaseModel# 定义 Pydantic 模型:描述创建商品的请求体结构
class ItemCreate(BaseModel):name: str # 商品名称(必填,字符串)price: float # 商品价格(必填,浮点数)is_offer: Optional[bool] = None # 是否打折(可选,布尔值,默认 None)category: str = "other" # 商品分类(可选,字符串,默认 "other")# 可选:添加模型配置,用于自定义文档或验证行为class Config:schema_extra = {# 文档中显示的示例请求体"example": {"name": "iPhone 15","price": 7999.99,"is_offer": True,"category": "electronics"}}
模型解释:
- 继承 BaseModel:所有 Pydantic 模型都必须继承
pydantic.BaseModel
,这是 Pydantic 模型的基类。 - 字段定义:
name: str
:必填字段,类型为字符串(无默认值表示必填)。price: float
:必填字段,类型为浮点数。is_offer: Optional[bool] = None
:可选字段,类型为布尔值,默认 None。category: str = "other"
:可选字段,类型为字符串,默认 “other”。
- Config 类:用于配置模型的额外行为,例如
schema_extra
用于在 API 文档中显示示例请求体,提升接口易用性。
5.3 接收请求体
定义好 Pydantic 模型后,我们可以在路径操作函数中直接使用该模型作为参数,FastAPI 会自动:
- 解析请求体中的 JSON 数据。
- 验证数据是否符合模型定义(类型、必填项等)。
- 若验证通过,将数据转换为模型实例,传递给函数;若失败,返回 422 错误。
新增“创建商品”的接口(使用 POST 方法):
# main.py(新增代码)
# 模拟数据库(实际项目中使用真实数据库)
fake_db = []@app.post("/items/", summary="创建商品", description="添加新商品到数据库")
def create_item(item: ItemCreate):"""创建商品:- **item**: 请求体,包含商品的名称、价格、是否打折、分类等信息- 返回:创建成功的商品信息(包含自动生成的 ID)"""# 将 Pydantic 模型转换为字典(方便添加额外字段)item_dict = item.dict()# 为商品添加自动生成的 ID(模拟数据库自增 ID)item_dict["id"] = len(fake_db) + 1# 存入模拟数据库fake_db.append(item_dict)# 返回创建的商品信息return item_dict
代码解释:
- 请求体参数:
item: ItemCreate
表示该参数是请求体,且结构需符合ItemCreate
模型。 - 模型转字典:
item.dict()
将 Pydantic 模型实例转换为 Python 字典,方便添加id
等数据库自动生成的字段。 - 模拟数据库:
fake_db
是一个列表,用于模拟数据库存储商品数据(后续章节会替换为真实数据库)。
5.4 测试请求体接口
由于 POST 请求无法直接通过浏览器 URL 访问,我们可以使用 FastAPI 自动生成的 Swagger UI 文档测试:
- 访问
http://127.0.0.1:8000/docs
,找到/items/
(POST 方法)的接口。 - 点击“Try it out”,此时会显示请求体的示例(来自
Config.schema_extra
)。 - 可修改示例数据(如
name: "MacBook Pro"
,price: 12999.0
),然后点击“Execute”发送请求。 - 查看响应结果,会返回包含自动生成
id
的商品信息:{"name": "MacBook Pro","price": 12999.0,"is_offer": true,"category": "electronics","id": 1 }
测试验证效果:
若传递不符合模型的数据(如 price: "abc"
),会返回 422 错误:
{"detail": [{"loc": ["body", "price"],"msg": "value is not a valid float","type": "type_error.float"}]
}
若未传递必填字段(如不传递 name
),也会返回 422 错误,提示“字段为必填项”。
5.5 嵌套 Pydantic 模型
实际项目中,请求体可能包含复杂结构(如“创建订单”时,订单中包含商品列表和用户信息),此时可通过“嵌套 Pydantic 模型”实现。
例如,定义“用户”模型和“包含用户信息的商品”模型:
# main.py(新增代码)
class User(BaseModel):username: str # 用户名(必填)email: str # 邮箱(必填)age: Optional[int] = None # 年龄(可选)class ItemWithUser(BaseModel):item: ItemCreate # 嵌套 ItemCreate 模型(必填)user: User # 嵌套 User 模型(必填)quantity: int = 1 # 数量(可选,默认 1)# 新增“创建带用户信息的商品”接口
@app.post("/items/with-user/", summary="创建带用户信息的商品")
def create_item_with_user(item_data: ItemWithUser):"""创建包含用户信息的商品"""# 转换为字典,添加 IDdata_dict = item_data.dict()data_dict["item"]["id"] = len(fake_db) + 1fake_db.append(data_dict["item"])# 返回完整数据return {"user": data_dict["user"],"item": data_dict["item"],"quantity": data_dict["quantity"]}
测试嵌套模型:
在 Swagger UI 中测试 /items/with-user/
接口,请求体示例如下:
{"item": {"name": "AirPods Pro","price": 1799.0,"is_offer": false,"category": "electronics"},"user": {"username": "zhangsan","email": "zhangsan@example.com","age": 25},"quantity": 2
}
发送请求后,会返回包含用户、商品、数量的完整响应,FastAPI 会自动验证嵌套模型的所有字段。
6. 响应处理:自定义响应状态码与响应体
API 不仅需要接收请求,还需要返回符合预期的响应。FastAPI 支持自定义响应状态码、响应头、响应体格式等,满足不同场景的需求。
6.1 自定义响应状态码
默认情况下,FastAPI 会根据 HTTP 方法自动设置响应状态码(如 GET 成功返回 200,POST 成功返回 201),但我们也可以手动指定状态码。
6.1.1 基础方式:通过 status_code
参数
在路径操作装饰器中添加 status_code
参数,指定响应状态码:
# main.py(修改创建商品接口)
from fastapi import status # 导入状态码常量@app.post("/items/", summary="创建商品", description="添加新商品到数据库",status_code=status.HTTP_201_CREATED # 手动指定状态码为 201(创建成功)
)
def create_item(item: ItemCreate):# 逻辑不变,省略...pass
为什么使用 status
常量?
FastAPI 提供 fastapi.status
模块,包含所有 HTTP 状态码的常量(如 HTTP_200_OK
、HTTP_201_CREATED
、HTTP_404_NOT_FOUND
),使用常量可避免手动写数字(如 201),提高代码可读性和可维护性。
6.1.2 动态设置状态码
若需要根据业务逻辑动态调整状态码(如“更新商品时,若商品不存在返回 404,存在则返回 200”),可在路径操作函数中返回 Response
对象或使用 HTTPException
(后续章节会详细讲)。
首先从 fastapi
导入 Response
:
from fastapi import FastAPI, Path, Query, status, Response # 新增 Response 导入
然后新增“更新商品”接口,动态设置状态码:
# main.py(新增代码)
@app.put("/items/{item_id}", summary="更新商品")
def update_item(item_id: int = Path(..., ge=1),item: ItemCreate,response: Response # 注入 Response 对象,用于动态设置状态码
):"""更新商品:- 若商品存在(item_id 在 fake_db 中),更新信息,返回 200- 若商品不存在,创建新商品,返回 201"""# 查找商品是否存在for index, existing_item in enumerate(fake_db):if existing_item["id"] == item_id:# 商品存在,更新信息updated_item = item.dict()updated_item["id"] = item_idfake_db[index] = updated_itemreturn updated_item # 默认返回 200# 商品不存在,创建新商品new_item = item.dict()new_item["id"] = item_idfake_db.append(new_item)response.status_code = status.HTTP_201_CREATED # 动态设置状态码为 201return new_item
测试动态状态码:
- 若
fake_db
中已有id=1
的商品,发送 PUT 请求http://127.0.0.1:8000/items/1
,响应状态码为 200。 - 若
fake_db
中没有id=10
的商品,发送 PUT 请求http://127.0.0.1:8000/items/10
,响应状态码为 201。
6.2 自定义响应体格式
默认情况下,FastAPI 会将函数返回值转换为 JSON 格式,但我们也可以自定义响应体的格式