Skip to content

路径操作高级配置

OpenAPI 操作 ID

Warning

如果你不是 OpenAPI 的 "专家",你可能不需要这个。

你可以使用参数 operation_id 为你的 路径操作 设置 OpenAPI operationId

你必须确保每个操作的 operationId 是唯一的。

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 覆盖每个 路径操作operationId

你应该在添加所有 路径操作 之后执行此操作。

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 中排除

要从生成的 OpenAPI 模式(以及自动文档系统)中排除一个 路径操作,请使用参数 include_in_schema 并将其设置为 False

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/", include_in_schema=False)
async def read_items():
    return [{"item_id": "Foo"}]

从文档字符串中获取高级描述

你可以限制从 路径操作函数 的文档字符串中用于 OpenAPI 的行数。

添加一个 \f(一个转义的 "换页" 字符)会导致 FastAPI 在此处截断用于 OpenAPI 的输出。

它不会显示在文档中,但其他工具(如 Sphinx)将能够使用其余部分。

from typing import Set, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: Set[str] = set()


@app.post("/items/", response_model=Item, summary="Create an item")
async def create_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_modelstatus_code

这定义了关于 路径操作 主要响应的元数据。

你还可以声明额外的响应及其模型、状态码等。

文档中有一个完整的章节关于它,你可以在 OpenAPI 中的额外响应 中阅读。

OpenAPI 额外信息

当你在你的应用程序中声明一个 路径操作 时,FastAPI 会自动生成相关的元数据,以便包含在 OpenAPI 模式中。

"技术细节"

在 OpenAPI 规范中,它被称为 Operation Object

它包含了关于 路径操作 的所有信息,并用于生成自动文档。

它包括 tagsparametersrequestBodyresponses 等。

这个 路径操作 特定的 OpenAPI 模式通常由 FastAPI 自动生成,但你也可以扩展它。

Tip

这是一个低级别的扩展点。

如果你只需要声明额外的响应,一个更方便的方法是使用 OpenAPI 中的额外响应

你可以使用参数 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"}]

如果你打开自动 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

在这个例子中,我们没有声明任何 Pydantic 模型。实际上,请求体甚至没有被 解析 为 JSON,而是直接作为 bytes 读取,函数 magic_data_reader() 将负责以某种方式解析它。

尽管如此,我们仍然可以声明请求体的预期模式。

自定义 OpenAPI 内容类型

使用同样的技巧,你可以使用 Pydantic 模型来定义 JSON Schema,然后将其包含在 路径操作 的自定义 OpenAPI 模式部分中。

即使请求中的数据类型不是 JSON,你也可以这样做。

例如,在这个应用程序中,我们没有使用 FastAPI 的集成功能从 Pydantic 模型中提取 JSON Schema,也没有使用自动的 JSON 验证。实际上,我们将请求内容类型声明为 YAML,而不是 JSON:

from typing import List

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
from typing import List

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.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.parse_obj(data)
    except ValidationError as e:
        raise HTTPException(status_code=422, detail=e.errors())
    return item

Info

在 Pydantic 版本 1 中,获取模型 JSON Schema 的方法称为 Item.schema(),在 Pydantic 版本 2 中,该方法称为 Item.model_json_schema()

尽管我们没有使用默认的集成功能,但我们仍然使用 Pydantic 模型手动生成了我们希望在 YAML 中接收的数据的 JSON Schema。

然后我们直接使用请求,并将主体提取为 bytes。这意味着 FastAPI 甚至不会尝试将请求负载解析为 JSON。

然后,在我们的代码中,我们直接解析 YAML 内容,然后再次使用相同的 Pydantic 模型来验证 YAML 内容:

from typing import List

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
from typing import List

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.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.parse_obj(data)
    except ValidationError as e:
        raise HTTPException(status_code=422, detail=e.errors())
    return item

Info

在 Pydantic 版本 1 中,解析和验证对象的方法是 Item.parse_obj(),在 Pydantic 版本 2 中,该方法称为 Item.model_validate()

Tip

在这里我们重用了相同的 Pydantic 模型。

但同样地,我们可以用其他方式验证它。