路径参数
你可以使用与 Python 格式化字符串相同的语法来声明路径"参数"或"变量":
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def item_details(item_id: int):
return {"item_id": item_id}
路径参数item_id
的值将作为参数item_id
传递给你的函数。在Swagger UI中的表现如下:
然后,我们可以访问http://127.0.0.1:8000/items/1
,将会看到如下响应:
{
"item_id": 1
}
另外,fastapi
还具有一个数据校验的功能,如果你通过浏览器访问http://127.0.0.1:8000/items/foo
,你会看到一个清晰可读的422 HTTP错误,如下:
{
"detail": [
{
"loc": [
"path",
"item_id"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}
因为路径参数item_id
传入的值为 “foo”,它不是一个int
,如果你提供的是float
而非整数也会出现同样的错误!
假设,有如下例子:
@app.get("/items/me")
async def items_me():
pass
@app.get("/items/{user_id}")
async def items_details(user_id):
pass
当我们访问http://127.0.0.1:8000/items/me
时,我们会发生永远都是走的第一个路由,这是因为路由操作是按顺序依次运行的。如果将@app.route("/items/{user_id}")
写在前面,那么/items/{user_id}
的路径还将与/items/me
相匹配,认为自己正在接收一个值为“me”的user_id参数!
fastapi
还支持使用Enum
来创建具有固定值的类属性参数,如下:
from enum import Enum
from fastapi import FastAPI
app = FastAPI()
class EnumParams(str, Enum):
Man = "man"
Woman = "woman"
@app.get("/people/{sex}")
async def people(sex: EnumParams):
return {"sex": sex}
当传递的位置参数不是EnumParams
设置的值时,将会校验不通过!
假设你有一个路径操作,它的路径为/files/{file_path}
,但是你需要file_path
自身也包含路径,比如/home/johndoe/myfile.txt
。因此,该文件的URL将类似于这样:/files/home/johndoe/myfile.txt
。
@app.get("/files/{path}")
async def people(path: str):
return {"path": path}
当我们访问localhost:8000/files/home/johndoe/myfile.txt
时,并不能如愿,而是返回了一个错误!这是因为不支持任何方式去声明路径参数以在其内部包含路径,因为这可能会导致难以测试和定义的情况出现。
不过,我们仍可以使用其他方式来实现它,如下:
@app.get("/files/{path: path}")
async def people(path: str):
return {"path": path}
当校验url非为path时,且没有其他路由与之匹配,那么将会返回404错误!
除了path
关键字之外,其他常用的定义类型的关键字如下:
str
: 表示参数为字符串int
: 表示参数为整型数字float
: 表示参数为浮点型数字uuid
: 表示参数为uuid
除了这些常用的关键字之外,我们还可以进行自定义。使用如下:
from fastapi import FastAPI
from starlette.convertors import Convertor
from starlette.convertors import register_url_convertor
class CustomConvertor(Convertor):
regex = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
def convert(self, value: str) -> str:
return str(value)
def to_string(self, value: str) -> str:
return str(value)
app = FastAPI()
register_url_convertor('custom', CustomConvertor())
@app.get("/items/{item_id:custom}")
async def item_details(item_id: str):
return {"item_id": item_id}
值得注意的是,在方法中定义的参数类型,需要与Convertor
中convert
方法返回的类型一致,否则将会引发422错误!!!
查询参数
声明不属于路径参数的其他函数参数时,它们将被自动解释为"查询字符串"参数
from fastapi import FastAPI
app = FastAPI()
data = [{"name": "zhangsan", "age": 1}, {"name": "lisi", "age": 2}]
@app.get("/people")
async def people(offset: int, limit: int):
return data[offset: offset+limit]
在Swagger UI中的表现形式如下:
查询字符串是键值对的集合,这些键值对位于URL
的?
之后,并以&
符号分隔。当我们访问http://localhost:8000/people?offset=0&limit=1
时,则会将offset与limit传递到对应的参数里边!
另外还可以对参数设置默认值,如下:
@app.get("/people")
async def people(offset: int, limit: int = 20):
return data[offset: offset+limit]
则当请求的url中未携带limit参数时,将默认为limit为20!
此外,我们还可以声明bool
类型的参数,他们将被自动转换,如下:
@app.get("/people")
async def people(is_woman: bool):
return {"woman": is_woman}
当我们访问如下url时,都将会把参数的值自动转换为True
:
http://localhost:8000/people?is_woman=1
http://localhost:8000/people?is_woman=True
http://localhost:8000/people?is_woman=true
http://localhost:8000/people?is_woman=yes
http://localhost:8000/people?is_woman=on
当路径参数和查询参数同时存在时,如下:
@app.get("/people/{id}")
async def people(id: int, is_woman: bool):
return {"woman": is_woman}
可同时存在多个路径参数和查询参数,并且不需要以任何特定的顺序来声明!
有的时候,我们可能会需要接收一个List
的数据,就像这样:http://localhost:8000/users?id=1&id=2
,在FastAPI
中,我们可以这么定义,如下:
@app.get("/users")
async def user_list(id: List[int]):
pass
请求体参数
当你需要将数据从客户端(例如浏览器)发送给API
时,你将其作为「请求体」发送。请求体是客户端发送给API
的数据。响应体是API
发送给客户端的数据。你的API
几乎总是要发送响应体。但是客户端并不总是需要发送请求体。我们使用Pydantic
模型来声明请求体,并能够获得它们所具有的所有能力和优点。安装如下:
pip install pydantic
然后在对其进行导入,使用如下:
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str|None = None
price: float
tax: float|None = None
@app.post("/items/")
async def create_item(item: Item):
return item
在Swagger UI中的表现形式如下: