FastAPI 路径参数与数值校验(Path Parameters & Numeric Validations)完整指南
【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi
本文基于 FastAPI 官方教程(本仓库 docs/hi/docs/tutorial/path-params-numeric-validations.md)整理而成。与 Query 参数类似,FastAPI 允许开发者通过Path为路径参数声明同样的 metadata 与校验规则(包括gt、ge、lt、le四种数值约束),并结合Annotated优雅地规避 Python 默认参数顺序问题。读完本文,你将掌握如何为路径参数附加title、数值上下限约束,理解参数声明顺序的三种解决手段,以及这些声明最终如何映射到 Pydantic 校验与 OpenAPI 文档。
前置准备:导入Path与Annotated
想为路径参数声明校验与 metadata,第一步是像Query一样从fastapi导入Path,并同时导入typing中的Annotated:
from typing import Annotated from fastapi import FastAPI, Path, Query app = FastAPI() @app.get("/items/{item_id}") async def read_items( item_id: Annotated[int, Path(title="The ID of the item to get")], q: Annotated[str | None, Query(alias="item-query")] = None, ): results = {"item_id": item_id} if q: results.update({"q": q}) return results完整源码见 docs_src/path_params_numeric_validations/tutorial001_an_py310.py。
版本注意:FastAPI 自 0.95.0 起加入对
Annotated的支持(并开始推荐使用)。若你的版本较旧,使用Annotated会遇到错误。请先参考 docs/hi/docs/deployment/versions.md 中 “Upgrading the FastAPI versions” 一节,将 FastAPI 至少升级到 0.95.1。
为路径参数声明 Metadata
与 Query 参数完全一样,你可以在Path()中传递title等 metadata 参数,为路径参数item_id声明人类可读的标题:
item_id: Annotated[int, Path(title="The ID of the item to get")]该title会出现在自动生成的 OpenAPI schema 中。从本仓库的测试断言可以看到,Path(title="The ID of the item to get")在/openapi.json中对应参数 schema 的"title": "The ID of the item to get"(见 tests/test_tutorial/test_path_params_numeric_validations/test_tutorial004.py)。
注意:路径参数永远是必填的。路径参数本身就是 URL 路径的一部分,因此无论你将其声明为
None,还是给它一个默认值,都不会改变其“必须出现在请求路径中”这一事实。教程 docs/hi/docs/tutorial/path-params-numeric-validations.md 中也明确强调:给路径参数设默认值是无效的,它始终是 required。这一点同样可以从源码中得到印证——fastapi/param_functions.py 中Path的default与default_factory参数在文档字符串中明确写着“This doesn't affectPathparameters as the value is always required”,它们仅为兼容性而保留。
按需调整参数的声明顺序
教程给出了一个值得注意的 Python 语法场景。假设你想把 query 参数q声明为必填的str——由于没有任何额外声明,你并不需要Query();但路径参数item_id又必须使用Path()才能附加校验与 metadata。
不推荐:默认值参数排在无默认值参数之前
如果坚持不使用Annotated,而写成下面的形式,Python 解释器会直接报错,因为 Python 不允许“有默认值的参数”位于“无默认值的参数”之前:
# 这会在函数定义阶段触发 Python 语法错误:non-default argument follows default argument async def read_items( item_id: int = Path(title="The ID of the item to get"), q: str, ):方案一:调整顺序,把无默认值的q放在前面
对 FastAPI 来说,参数声明顺序并不重要——它会依据参数名、类型以及Query、Path等 default 声明来识别每个参数。因此你可以把没有默认值的q放在前面,把带有= Path(...)的item_id放在后面:
from fastapi import FastAPI, Path app = FastAPI() @app.get("/items/{item_id}") async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")): results = {"item_id": item_id} if q: results.update({"q": q}) return results完整源码见 docs_src/path_params_numeric_validations/tutorial002_py310.py。
方案二(推荐):使用Annotated
一旦改用Annotated,校验信息不再占用函数参数的 default value 槽位,因此不存在“default 参数排在前面的问题”,顺序也就变得随意、自由:
from typing import Annotated from fastapi import FastAPI, Path app = FastAPI() @app.get("/items/{item_id}") async def read_items( q: str, item_id: Annotated[int, Path(title="The ID of the item to get")] ): results = {"item_id": item_id} if q: results.update({"q": q}) return results完整源码见 docs_src/path_params_numeric_validations/tutorial002_an_py310.py。注意这里q在前、item_id在后,顺序刻意与上一个示例相反,但语义完全一致。
参数顺序小技巧:*关键字参数分隔符
教程还介绍了一个“小技巧”(通常不常用):当你想同时满足以下四个条件时——
q不加Query()也没有默认值;item_id必须通过Path()声明;- 参数顺序需要任意摆放;
- 不想用
Annotated;
——可以借 Python 的特殊语法:把*作为函数第一个参数传入。Python 不会对*本身做任何处理,但它宣告:其后所有参数都只能以关键字参数(keyword arguments,即 kwargs)方式传入,即使它们本身没有默认值:
from fastapi import FastAPI, Path app = FastAPI() @app.get("/items/{item_id}") async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str): results = {"item_id": item_id} if q: results.update({"q": q}) return results完整源码见 docs_src/path_params_numeric_validations/tutorial003_py310.py。
使用Annotated时则更简单
若使用Annotated,由于不占用函数参数默认值,你连*都不需要:
from typing import Annotated from fastapi import FastAPI, Path app = FastAPI() @app.get("/items/{item_id}") async def read_items( item_id: Annotated[int, Path(title="The ID of the item to get")], q: str ): results = {"item_id": item_id} if q: results.update({"q": q}) return results完整源码见 docs_src/path_params_numeric_validations/tutorial003_an_py310.py。
数值校验:ge(greater than or equal)
与Query一样,Path(以及后续教程中出现的其它参数声明类)也支持数值约束。例如ge=1表示item_id必须是“greater than orequal to 1”(大于或等于 1)的整数:
from typing import Annotated from fastapi import FastAPI, Path app = FastAPI() @app.get("/items/{item_id}") async def read_items( item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str ): results = {"item_id": item_id} if q: results.update({"q": q}) return results完整源码见 docs_src/path_params_numeric_validations/tutorial004_an_py310.py。
这一约束同时作用于校验层与文档层:
- 校验层:请求
/items/0?q=somequery时,路径参数0不满足ge=1,FastAPI 返回422,错误详情为"Input should be greater than or equal to 1",错误类型为greater_than_equal,ctx中携带{"ge": 1}(见 tests/test_tutorial/test_path_params_numeric_validations/test_tutorial004.py)。 - 文档层:
ge=1会渲染为 OpenAPI schema 中的"minimum": 1(见同文件 test_openapi_schema 的 snapshot 断言)。
数值校验:gt与le
同样的机制适用于另外两个约束:
gt:greaterthan,严格大于;le:less than orequal,小于等于。
示例中gt=0, le=1000表示item_id必须大于 0 且小于等于 1000:
from typing import Annotated from fastapi import FastAPI, Path app = FastAPI() @app.get("/items/{item_id}") async def read_items( item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)], q: str, ): results = {"item_id": item_id} if q: results.update({"q": q}) return results完整源码见 docs_src/path_params_numeric_validations/tutorial005_an_py310.py。
数值校验作用于浮点数:gt与lt
数值校验同样适用于float值。也正是此时,能够声明严格大于gt(而不仅是大于等于ge)才显得重要:例如我们可以要求某个值大于0,即便它小于1也是合法的。
看下面这个综合示例——路径参数item_id使用ge=0, le=1000,query 参数size使用Query(gt=0, lt=10.5):
from typing import Annotated from fastapi import FastAPI, Path, Query app = FastAPI() @app.get("/items/{item_id}") async def read_items( *, item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)], q: str, size: Annotated[float, Query(gt=0, lt=10.5)], ): results = {"item_id": item_id} if q: results.update({"q": q}) if size: results.update({"size": size}) return results完整源码见 docs_src/path_params_numeric_validations/tutorial006_an_py310.py。
对浮点数而言:
0.5是合法值(大于 0 且小于 10.5);0.0或0非法,因为不满足严格的gt=0;- 反过来
lt同理:10.5本身非法,因为它要求严格小于 10.5。
这些边界行为在仓库测试中都有精确断言(见 tests/test_tutorial/test_path_params_numeric_validations/test_tutorial006.py):
| 请求 | 校验结果 | 错误类型 |
|---|---|---|
/items/-1?q=somequery&size=5 | item_id小于ge=0 | greater_than_equal,消息 "Input should be greater than or equal to 0" |
/items/1001?q=somequery&size=5 | item_id大于le=1000 | less_than_equal,消息 "Input should be less than or equal to 1000" |
/items/1?q=somequery&size=0.0 | size不满足gt=0 | greater_than,消息 "Input should be greater than 0" |
/items/1?q=somequery&size=10.5 | size不满足lt=10.5 | less_than,消息 "Input should be less than 10.5" |
而在 OpenAPI 文档侧(同样由该文件的test_openapi_schema快照断言):
ge=0→"minimum": 0,le=1000→"maximum": 1000;gt=0→"exclusiveMinimum": 0,lt=10.5→"exclusiveMaximum": 10.5;size对应的 schema 类型是"number"(浮点数)。
参数声明的统一家族:Query、Path与Param
教程的 Recap 与“技术细节”两个小结串起了整套设计,值得展开说明:
Query、Path以及后续章节出现的其它参数类,都是同一个公共Param类的子类(见 docs/hi/docs/tutorial/path-params-numeric-validations.md 的 note)。因此它们共享同一套用于附加校验与 metadata 的参数。在本仓库中,这一设计在源码中清晰可见:fastapi/params.py 中的Param类统一接收并持有gt、ge、lt、le、min_length、max_length、pattern、title、examples等全部参数,并通过 FieldInfo 下传给 Pydantic 用于校验与 schema 生成。也就是说,你在Path上学到的全部约束能力,都可以原样复用到Query、Header、Cookie等场景。
Query、Path从fastapi导入时,本质上不是类而是函数。当你调用它们时,返回的是与函数同名的类的实例——例如导入的是名为Query的 function,调用Query(...)后得到的是Queryclass 的 instance。之所以用函数而不是直接暴露类,是为了避免编辑器/类型检查器因为Query等类需要类型参数(泛型)而在你的代码上标注类型错误,让你无需添加额外的类型忽略配置,就能在常规编辑器与工具链中顺畅工作。这一点在 fastapi/param_functions.py 中有直接体现:def Path(...)(第 13 行)与def Query(...)(第 357 行)都是大写命名的函数定义,其中gt、ge、lt、le均被声明为可选的float | None参数。
小结:四种数值约束速查
| 参数 | 含义 | OpenAPI 映射 | Pydantic 校验 |
|---|---|---|---|
gt | greaterthan(大于) | exclusiveMinimum | greater_than |
ge | greater than orequal(大于等于) | minimum | greater_than_equal |
lt | lessthan(小于) | exclusiveMaximum | less_than |
le | less than orequal(小于等于) | maximum | less_than_equal |
字符串类校验(如min_length、max_length、pattern)与 metadata(如title、description)的声明方式,则与 Query 参数与字符串校验 完全一致,可互为参照。
进一步阅读
- 全部本教程源码示例:docs_src/path_params_numeric_validations/
Param类的统一参数定义:fastapi/params.pyPath、Query函数的完整签名:fastapi/param_functions.py- 仓库回归测试(含边界值与 OpenAPI schema 断言):tests/test_tutorial/test_path_params_numeric_validations/
【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考