路径操作的高级配置¶
🌐 Translation by AI and humans
This translation was made by AI guided by humans. 🤝
It could have mistakes of misunderstanding the original meaning, or looking unnatural, etc. 🤖
You can improve this translation by helping us guide the AI LLM better.
OpenAPI 的 operationId¶
Warning
如果你并非 OpenAPI 的“专家”,你可能不需要这部分内容。
你可以在 路径操作 中通过参数 operation_id 设置要使用的 OpenAPI operationId。
务必确保每个操作的 operation_id 都是唯一的。
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", operation_id="some_specific_id_you_define")
async def read_items():
return [{"item_id": "Foo"}]
🤓 Other versions and variants
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", operation_id="some_specific_id_you_define")
async def read_items():
return [{"item_id": "Foo"}]
使用 路径操作函数 的函数名作为 operationId¶
如果你想用 API 的函数名作为 operationId,你可以遍历所有路径操作,并使用它们的 APIRoute.name 重写每个 路径操作 的 operation_id。
你应该在添加了所有 路径操作 之后执行此操作。
from fastapi import FastAPI
from fastapi.routing import APIRoute
app = FastAPI()
@app.get("/items/")
async def read_items():
return [{"item_id": "Foo"}]
def use_route_names_as_operation_ids(app: FastAPI) -> None:
"""
Simplify operation IDs so that generated API clients have simpler function
names.
Should be called only after all routes have been added.
"""
for route in app.routes:
if isinstance(route, APIRoute):
route.operation_id = route.name # in this case, 'read_items'
use_route_names_as_operation_ids(app)
🤓 Other versions and variants
from fastapi import FastAPI
from fastapi.routing import APIRoute
app = FastAPI()
@app.get("/items/")
async def read_items():
return [{"item_id": "Foo"}]
def use_route_names_as_operation_ids(app: FastAPI) -> None:
"""
Simplify operation IDs so that generated API clients have simpler function
names.
Should be called only after all routes have been added.
"""
for route in app.routes:
if isinstance(route, APIRoute):
route.operation_id = route.name # in this case, 'read_items'
use_route_names_as_operation_ids(app)
Tip
如果你手动调用 app.openapi(),你应该在此之前更新 operationId。
Warning
如果你这样做,务必确保你的每个 路径操作函数 的名字唯一。
即使它们在不同的模块中(Python 文件)。
从 OpenAPI 中排除¶
使用参数 include_in_schema 并将其设置为 False,来从生成的 OpenAPI 方案中排除一个 路径操作(这样一来,就从自动化文档系统中排除掉了):
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", include_in_schema=False)
async def read_items():
return [{"item_id": "Foo"}]
🤓 Other versions and variants
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", include_in_schema=False)
async def read_items():
return [{"item_id": "Foo"}]
来自 docstring 的高级描述¶
你可以限制 路径操作函数 的 docstring 中用于 OpenAPI 的行数。
添加一个 \f(一个“换页”的转义字符)可以使 FastAPI 在那一位置截断用于 OpenAPI 的输出。
剩余部分不会出现在文档中,但是其他工具(比如 Sphinx)可以使用剩余部分。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
@app.post("/items/", summary="Create an item")
async def create_item(item: Item) -> Item:
"""
Create an item with all the information:
- **name**: each item must have a name
- **description**: a long description
- **price**: required
- **tax**: if the item doesn't have tax, you can omit this
- **tags**: a set of unique tag strings for this item
\f
:param item: User input.
"""
return item
附加响应¶
你可能已经见过如何为一个 路径操作 声明 response_model 和 status_code。
这定义了该 路径操作 主响应的元数据。
你也可以为它声明带有各自模型、状态码等的附加响应。
文档中有一个完整章节,你可以阅读这里的OpenAPI 中的附加响应。
OpenAPI Extra¶
当你在应用中声明一个 路径操作 时,FastAPI 会自动生成与该 路径操作 相关的元数据,以包含到 OpenAPI 方案中。
技术细节
在 OpenAPI 规范中,这被称为 Operation 对象。
它包含关于该 路径操作 的所有信息,并用于生成自动文档。
它包括 tags、parameters、requestBody、responses 等。
这个特定于 路径操作 的 OpenAPI 方案通常由 FastAPI 自动生成,但你也可以扩展它。
你可以使用参数 openapi_extra 扩展某个 路径操作 的 OpenAPI 方案。
OpenAPI 扩展¶
例如,这个 openapi_extra 可用于声明 OpenAPI 扩展:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", openapi_extra={"x-aperture-labs-portal": "blue"})
async def read_items():
return [{"item_id": "portal-gun"}]
🤓 Other versions and variants
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", openapi_extra={"x-aperture-labs-portal": "blue"})
async def read_items():
return [{"item_id": "portal-gun"}]
当你打开自动 API 文档时,你的扩展会显示在该 路径操作 的底部。

如果你查看最终生成的 OpenAPI(在你的 API 的 /openapi.json),你也会看到你的扩展作为该 路径操作 的一部分:
{
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
},
"paths": {
"/items/": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
},
"x-aperture-labs-portal": "blue"
}
}
}
}
自定义 OpenAPI 路径操作方案¶
openapi_extra 中的字典会与该 路径操作 自动生成的 OpenAPI 方案进行深度合并。
因此,你可以在自动生成的方案上添加额外数据。
例如,你可以决定用自己的代码读取并验证请求,而不使用 FastAPI 与 Pydantic 的自动功能,但你仍然希望在 OpenAPI 方案中定义该请求。
你可以用 openapi_extra 来做到:
from fastapi import FastAPI, Request
app = FastAPI()
def magic_data_reader(raw_body: bytes):
return {
"size": len(raw_body),
"content": {
"name": "Maaaagic",
"price": 42,
"description": "Just kiddin', no magic here. ✨",
},
}
@app.post(
"/items/",
openapi_extra={
"requestBody": {
"content": {
"application/json": {
"schema": {
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"type": "string"},
"price": {"type": "number"},
"description": {"type": "string"},
},
}
}
},
"required": True,
},
},
)
async def create_item(request: Request):
raw_body = await request.body()
data = magic_data_reader(raw_body)
return data
🤓 Other versions and variants
from fastapi import FastAPI, Request
app = FastAPI()
def magic_data_reader(raw_body: bytes):
return {
"size": len(raw_body),
"content": {
"name": "Maaaagic",
"price": 42,
"description": "Just kiddin', no magic here. ✨",
},
}
@app.post(
"/items/",
openapi_extra={
"requestBody": {
"content": {
"application/json": {
"schema": {
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"type": "string"},
"price": {"type": "number"},
"description": {"type": "string"},
},
}
}
},
"required": True,
},
},
)
async def create_item(request: Request):
raw_body = await request.body()
data = magic_data_reader(raw_body)
return data
在这个示例中,我们没有声明任何 Pydantic 模型。事实上,请求体甚至没有被 解析 为 JSON,而是直接以 bytes 读取,并由函数 magic_data_reader() 以某种方式负责解析。
尽管如此,我们仍然可以声明请求体的预期方案。
自定义 OpenAPI 内容类型¶
使用同样的技巧,你可以用一个 Pydantic 模型来定义 JSON Schema,然后把它包含到该 路径操作 的自定义 OpenAPI 方案部分中。
即使请求中的数据类型不是 JSON,你也可以这样做。
例如,在这个应用中我们不使用 FastAPI 集成的从 Pydantic 模型提取 JSON Schema 的功能,也不使用对 JSON 的自动校验。实际上,我们将请求的内容类型声明为 YAML,而不是 JSON:
import yaml
from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel, ValidationError
app = FastAPI()
class Item(BaseModel):
name: str
tags: list[str]
@app.post(
"/items/",
openapi_extra={
"requestBody": {
"content": {"application/x-yaml": {"schema": Item.model_json_schema()}},
"required": True,
},
},
)
async def create_item(request: Request):
raw_body = await request.body()
try:
data = yaml.safe_load(raw_body)
except yaml.YAMLError:
raise HTTPException(status_code=422, detail="Invalid YAML")
try:
item = Item.model_validate(data)
except ValidationError as e:
raise HTTPException(status_code=422, detail=e.errors(include_url=False))
return item
🤓 Other versions and variants
import yaml
from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel, ValidationError
app = FastAPI()
class Item(BaseModel):
name: str
tags: list[str]
@app.post(
"/items/",
openapi_extra={
"requestBody": {
"content": {"application/x-yaml": {"schema": Item.model_json_schema()}},
"required": True,
},
},
)
async def create_item(request: Request):
raw_body = await request.body()
try:
data = yaml.safe_load(raw_body)
except yaml.YAMLError:
raise HTTPException(status_code=422, detail="Invalid YAML")
try:
item = Item.model_validate(data)
except ValidationError as e:
raise HTTPException(status_code=422, detail=e.errors(include_url=False))
return item
尽管我们没有使用默认的集成功能,我们仍然使用 Pydantic 模型手动生成我们想以 YAML 接收的数据的 JSON Schema。
然后我们直接使用请求并将请求体提取为 bytes。这意味着 FastAPI 甚至不会尝试将请求负载解析为 JSON。
接着在我们的代码中,我们直接解析该 YAML 内容,然后再次使用同一个 Pydantic 模型来验证该 YAML 内容:
import yaml
from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel, ValidationError
app = FastAPI()
class Item(BaseModel):
name: str
tags: list[str]
@app.post(
"/items/",
openapi_extra={
"requestBody": {
"content": {"application/x-yaml": {"schema": Item.model_json_schema()}},
"required": True,
},
},
)
async def create_item(request: Request):
raw_body = await request.body()
try:
data = yaml.safe_load(raw_body)
except yaml.YAMLError:
raise HTTPException(status_code=422, detail="Invalid YAML")
try:
item = Item.model_validate(data)
except ValidationError as e:
raise HTTPException(status_code=422, detail=e.errors(include_url=False))
return item
🤓 Other versions and variants
import yaml
from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel, ValidationError
app = FastAPI()
class Item(BaseModel):
name: str
tags: list[str]
@app.post(
"/items/",
openapi_extra={
"requestBody": {
"content": {"application/x-yaml": {"schema": Item.model_json_schema()}},
"required": True,
},
},
)
async def create_item(request: Request):
raw_body = await request.body()
try:
data = yaml.safe_load(raw_body)
except yaml.YAMLError:
raise HTTPException(status_code=422, detail="Invalid YAML")
try:
item = Item.model_validate(data)
except ValidationError as e:
raise HTTPException(status_code=422, detail=e.errors(include_url=False))
return item
Tip
这里我们复用了同一个 Pydantic 模型。
但同样地,我们也可以用其他方式对其进行验证。