跳到内容

路径操作高级配置

OpenAPI operationId

警告

如果您不是 OpenAPI 的“专家”,您可能不需要此功能。

您可以使用参数 operation_id 来设置您的 路径操作 中使用的 OpenAPI 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 来覆盖每个 路径操作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)

提示

如果您手动调用 app.openapi(),您应该在此之前更新 operationId

警告

如果您这样做,您必须确保您的每个 路径操作函数 都具有唯一的名称。

即使它们位于不同的模块(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 Extra

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

技术细节

在 OpenAPI 规范中,它被称为 操作对象

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

它包括 tagsparametersrequestBodyresponses 等。

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

提示

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

如果您只需要声明额外的响应,更便捷的方法是使用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 模式,然后将其包含在 路径操作 的自定义 OpenAPI 模式部分中。

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

例如,在此应用程序中,我们不使用 FastAPI 的集成功能从 Pydantic 模型中提取 JSON 模式,也不使用 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

信息

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

尽管如此,虽然我们没有使用默认的集成功能,我们仍然使用 Pydantic 模型手动生成 JSON 模式,用于我们希望以 YAML 格式接收的数据。

然后我们直接使用请求,并将请求体提取为 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

信息

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

提示

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

但是,以同样的方式,我们也可以通过其他方式验证它。