内容小记:
- 路径参数Path Parameter使用(类型验证与转换、包含
/
的文件路径、预定义值,Annotated使用与int范围限定)
- 查询参数Query Parameter使用(默认值、可选参数、类型验证与转换、Annotated使用与str格式限定)
注:本文所有代码在python3.11下验证
路径参数(Path Parameter)
路径参数或变量 可以使用与Python格式化字符串相同的语法来声明:
| from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def item(item_id):
return {"item_id": item_id}
|
而后就可以通过 127.0.0.1/items/1+1=10 进行访问。浏览器显示内容如下:
类型验证与转换
上面的例子中,item_id
内容比较随意。借助FastAPI底层使用的Pydantic,可以指定类型(比如int
):
| from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def item(item_id: int):
return {"item_id": item_id}
|
此时用浏览器访问 127.0.0.1/items/1+1=10,将会遇到错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | {
"detail": [
{
"type": "int_parsing",
"loc": [
"path",
"item_id"
],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "1+1=10",
"url": "https://errors.pydantic.dev/2.5/v/int_parsing"
}
]
}
|
而 127.0.0.1/items/1 将会看到正确的结果
同样,试图访问 127.0.0.1/items/1.2 也会将会看到错误的结果,要兼容int和float,需要改为
| @app.get("/items/{item_id}")
async def item(item_id: float):
return {"item_id": item_id}
|
这些校验工作都是由Pydantic
完成的。
顺序
使用路径操作函数时,如果由固定路径需要处理。要确保先声明固定路径:
| from fastapi import FastAPI
app = FastAPI()
@app.get("/items/1+1=10")
async def item0():
return {"item_id": "1+1=10"}
@app.get("/items/{item_id}")
async def item(item_id: float):
return {"item_id": item_id}
|
文件路径(路径转换符)
如果要提取 127.0.0.1:8000/files/aa/bb.txt
中的路径aa\bb.txt
怎么办?
这么写是不行的
| from fastapi import FastAPI
app = FastAPI()
@app.get("/files/{fp}")
async def get_file(fp):
return {"file": fp}
|
需要像下面这样,指定转换符path
,提取变量才能包含/
符号:
| from fastapi import FastAPI
app = FastAPI()
@app.get("/files/{fp:path}")
async def get_file(fp):
return {"file": fp}
|
限定字符串取值(预定值)
如何限定,只允许路径变量取几个特定值,比如部门,只能在hr、finance、rd中选择。
首先想到的是,这么尝试:
| from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/departments/{department_name}")
async def deal_with_department(department_name):
if department_name not in ["hr", "finance", "rd"]:
raise HTTPException(status_code=404, detail="Department not found")
return {"name": department_name}
|
工作起来没问题,不存在的部门直接报404异常。
不过,FastAPI中是这么用的:
1
2
3
4
5
6
7
8
9
10
11
12
13 | from enum import Enum
from fastapi import FastAPI, HTTPException
app = FastAPI()
class DepartmentName(str, Enum):
hr = "hr"
finance = "finance"
rd = "rd"
@app.get("/departments/{department_name}")
async def deal_with_department(department_name : DepartmentName):
return {"name": department_name}
|
使用Enum的好处是,通过127.0.0.1:8000\docs
访问文档时,更友好:
限定路径参数值范围
如何要确保有效的路径参数值大小10~100之间,该怎么办?
- https://fastapi.tiangolo.com/reference/parameters/
FastAPI利用的python中的Annotated功能,来给类型增加注解信息:
| from fastapi import FastAPI, Path
from typing import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def get_item(item_id: Annotated[int, Path(title="The ID of the item to get", ge=10, le=100)]):
return {"item": item_id}
|
127.0.0.1/items/1
无效
127.0.0.1/items/101
无效
127.0.0.1/items/20
有效
注意:注解信息中用的Path,注意和下面查询参数中的Query区分
查询参数(Query Parameter)
查询参数是键值对,位于URL的?
之后。不同的参数用&
进行分隔。
FastAPI的处理逻辑是:路径处理函数中声明的参数,如果不是路径参数,将自动解释为查询参数。
获取查询参数
比如,要获取 127.0.0.1:8001/items/?item_id=111
中的查询参数,可以:
| from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/items/")
async def get_item(item_id: int):
return {"item": item_id}
|
默认值
查询参数可以指定默认值,比如item_id: int = 1
:
| from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/items/")
async def get_item(item_id: int = 1):
return {"item": item_id}
|
这样一来,下面两个写法等价:
127.0.0.1:8001/items/
127.0.0.1:8001/items/?item_id=1
可选参数
注意与默认值概念区分。将默认值设置为None
来声明可选查询参数:
| @app.get("/items/")
async def get_item(item_id: int | None = None):
if item_id:
return {"item": item_id}
return "items"
|
这样一来:
127.0.0.1:8001/items/
127.0.0.1:8001/items/?item_id=1
不再等价。
注意:|
说明 item_id
可以是int,也可以是None类型。
类型校验与转换
比如,下面的例子:我们定义参数bool类型:
| from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/items/{item_id}")
async def get_item(item_id, d: bool):
item = {"item_id": item_id}
if d:
item.update({"description": "Demo from 1+1=10"})
return item
|
下面的都是等价的:
127.0.0.1:8001/items/111?d=1
127.0.0.1:8001/items/111?d=on
127.0.0.1:8001/items/111?d=yes
127.0.0.1:8001/items/111?d=true
127.0.0.1:8001/items/111?d=True
- ...
注意:0 对应False,1对应True。其他数字不会转成bool。
字符串验证
如何要确保有效的查询参数的长度在3~10之间,该怎么办?
FastAPI利用的python中的Annotated功能,来给类型增加注解信息(注意,对于查询参数,用的Query):
| from fastapi import FastAPI, Query
from typing import Annotated
app = FastAPI()
@app.get("/items/")
async def get_item(item_id: Annotated[str, Query(max_length=10, min_length=3)]):
return {"item": item_id}
|
127.0.0.1:8001/items/?item_id=1
无效
127.0.0.1:8001/items/?item_id=11111111111111111111
无效
127.0.0.1:8001/items/?item_id=1111
有效
使用Annotated注解时,依然可以将参数设置为可选:
| @app.get("/items/")
async def get_item(item_id: Annotated[str | None, Query(max_length=10, min_length=3)]=None):
if item_id:
return {"item": item_id}
return "items"
|
另外,还可以使用正则表达式来限定查询参数的格式,比如:
| from fastapi import FastAPI, Query
from typing import Annotated
app = FastAPI()
@app.get("/items/")
async def get_item(item_id: Annotated[str | None, Query(max_length=10, min_length=3, pattern=r'\w+\W+\w+')]=None):
if item_id:
return {"item": item_id}
return "items"
|
127.0.0.1:8001/items/?item_id=11-11
有效
127.0.0.1:8001/items/?item_id=1111
无效
参考
- https://fastapi.tiangolo.com
- https://asgi.readthedocs.io/en/latest/introduction.html
- https://www.starlette.io
- https://docs.pydantic.dev/latest/
- https://fastapi.tiangolo.com/reference/parameters/