路径参数¶
您可以使用与 Python 格式字符串相同的语法声明路径“参数”或“变量”。
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id):
return {"item_id": item_id}
路径参数 item_id
的值将作为参数 item_id
传递给您的函数。
因此,如果您运行此示例并访问 http://127.0.0.1:8000/items/foo,您将看到以下响应
{"item_id":"foo"}
带类型的路径参数¶
您可以使用标准的 Python 类型注解,在函数中声明路径参数的类型。
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
在本例中,item_id
被声明为 int
。
检查
这将为您在函数内部提供编辑器支持,并带有错误检查、补全等功能。
数据转换¶
如果您运行此示例并在浏览器中打开 http://127.0.0.1:8000/items/3,您将看到以下响应
{"item_id":3}
检查
请注意,您的函数接收(并返回)的值是 3
,它是 Python int
,而不是字符串 "3"
。
因此,使用该类型声明,**FastAPI** 会为您提供自动的请求"解析"。
数据验证¶
但是,如果您在浏览器中访问 http://127.0.0.1:8000/items/foo,您将看到一个友好的 HTTP 错误
{
"detail": [
{
"type": "int_parsing",
"loc": [
"path",
"item_id"
],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
"url": "https://errors.pydantic.dev/2.1/v/int_parsing"
}
]
}
因为路径参数 item_id
的值为 "foo"
,它不是一个 int
。
如果您提供的是 float
而不是 int
,也会出现相同的错误,例如: http://127.0.0.1:8000/items/4.2
检查
因此,使用相同的 Python 类型声明,**FastAPI** 为您提供了数据验证。
请注意,该错误还清楚地指出了验证未通过的确切位置。
这在开发和调试与您的 API 交互的代码时非常有用。
文档¶
当您在浏览器中打开 http://127.0.0.1:8000/docs 时,您将看到类似于以下内容的自动、交互式 API 文档
检查
同样,仅使用相同的 Python 类型声明,**FastAPI** 就会为您提供自动的、交互式的文档(集成了 Swagger UI)。
请注意,路径参数被声明为整数。
基于标准的好处,替代文档¶
由于生成的模式来自 OpenAPI 标准,因此存在许多兼容的工具。
因此,**FastAPI** 本身提供了另一种 API 文档(使用 ReDoc),您可以在 http://127.0.0.1:8000/redoc 访问它。
同样,还有许多兼容的工具。包括针对多种语言的代码生成工具。
Pydantic¶
所有数据验证都在幕后由 Pydantic 执行,因此您可以享受它带来的所有好处。您知道自己处于安全可靠的状况下。
您可以对 str
、float
、bool
以及许多其他复杂数据类型使用相同的类型声明。
教程的下一章将探讨其中一些类型。
顺序很重要¶
在创建路径操作时,您可能会遇到路径固定的情况。
例如/users/me
,假设它是用于获取当前用户数据的。
然后您还可以使用路径/users/{user_id}
来根据用户 ID 获取特定用户的数据。
由于路径操作按顺序进行评估,因此您需要确保/users/me
的路径在/users/{user_id}
的路径之前声明。
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/me")
async def read_user_me():
return {"user_id": "the current user"}
@app.get("/users/{user_id}")
async def read_user(user_id: str):
return {"user_id": user_id}
否则,/users/{user_id}
的路径也会匹配/users/me
,认为它正在接收一个名为user_id
的参数,其值为"me"
。
同样,您不能重新定义路径操作。
from fastapi import FastAPI
app = FastAPI()
@app.get("/users")
async def read_users():
return ["Rick", "Morty"]
@app.get("/users")
async def read_users2():
return ["Bean", "Elfo"]
由于第一个路径首先匹配,因此它将始终被使用。
预定义值¶
如果您有一个接收路径参数的路径操作,但您希望可能的有效路径参数值是预定义的,那么可以使用标准的 Python Enum
。
创建Enum
类¶
导入Enum
并创建一个从str
和Enum
继承的子类。
通过从str
继承,API 文档将能够知道这些值必须是string
类型,并且能够正确渲染。
然后创建具有固定值的类属性,这些属性将是可用的有效值。
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}
信息
枚举(或枚举)在 Python 中自版本 3.4 起可用。
提示
如果您想知道,“AlexNet”、“ResNet”和“LeNet”只是机器学习 模型 的名称。
声明路径参数¶
然后使用您创建的枚举类 (ModelName
) 创建一个路径参数,并使用类型注释。
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}
检查文档¶
由于路径参数的可用值是预定义的,因此交互式文档可以很好地显示它们。
使用 Python 枚举¶
路径参数的值将是枚举成员。
比较枚举成员¶
您可以将其与您创建的枚举ModelName
中的枚举成员进行比较。
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}
获取枚举值¶
您可以使用model_name.value
获取实际值(在本例中为str
),或者一般来说,your_enum_member.value
。
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}
提示
您还可以使用ModelName.lenet.value
访问值"lenet"
。
返回枚举成员¶
您可以从路径操作中返回枚举成员,即使嵌套在 JSON 主体中(例如,dict
)。
在返回给客户端之前,它们将被转换为其对应值(在本例中为字符串)。
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}
在您的客户端中,您将获得一个类似的 JSON 响应。
{
"model_name": "alexnet",
"message": "Deep Learning FTW!"
}
包含路径的路径参数¶
假设您有一个带有路径/files/{file_path}
的路径操作。
但是您需要file_path
本身包含一个路径,例如home/johndoe/myfile.txt
。
因此,该文件的 URL 将类似于:/files/home/johndoe/myfile.txt
。
OpenAPI 支持¶
OpenAPI 不支持声明一个包含路径的路径参数,因为这可能会导致难以测试和定义的情况。
但是,您仍然可以在 FastAPI 中使用 Starlette 的内部工具之一来实现。
并且文档仍然可以正常工作,尽管没有添加任何说明参数应包含路径的文档。
路径转换器¶
使用 Starlette 的直接选项,您可以使用类似于以下 URL 的声明包含路径的路径参数。
/files/{file_path:path}
在本例中,参数的名称是file_path
,最后部分:path
表示该参数应匹配任何路径。
因此,您可以将其与以下内容一起使用。
from fastapi import FastAPI
app = FastAPI()
@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
return {"file_path": file_path}
提示
您可能需要参数包含/home/johndoe/myfile.txt
,并带有前导斜杠 (/
)。
在这种情况下,URL 将是:/files//home/johndoe/myfile.txt
,在files
和home
之间有两个斜杠 (//
)。
总结¶
使用 FastAPI,通过使用简短、直观且标准的 Python 类型声明,您可以获得
- 编辑器支持:错误检查、自动完成等。
- 数据 "解析"
- 数据验证
- API 注释和自动文档
您只需声明一次。
这可能是 FastAPI 与其他框架相比的主要可见优势(除了原始性能之外)。