首页
/ FastAPI 通用实战配方:响应数据过滤与性能优化、OpenAPI 文档定制与 JSON 兼容编码

FastAPI 通用实战配方:响应数据过滤与性能优化、OpenAPI 文档定制与 JSON 兼容编码

2026-09-06 16:35:31作者:薛曦旖Francesca

本文基于 FastAPI 官方文档的 General How-To Recipes 章节,把这份“通用问题速查”中的 10 个高频主题逐一展开:如何通过响应模型过滤敏感数据、如何利用 Pydantic 的 Rust 序列化提升 JSON 性能、如何为 path operations 配置 Tags / Summary / Description / 弃用标记、如何用 jsonable_encoder 把任意对象转换为 JSON 兼容结构、以及如何定制 OpenAPI 元数据与文档 URL。读完后,你能为项目中的每个 path operation 直接套用一套经过仓库示例与源码印证过的配置配方。

General Recipes 的定位

FastAPI 文档中的 How To - Recipes 章节收录的是若干相互独立的“配方”,大多数情况下你只需要在问题直接命中你的项目时才去查阅。本篇对应的 General 页面正是其中的“综合速查表”,它把若干通用或高频问题指向文档中的对应章节。下文按原文档的条目顺序,将每个配方补全为可复制的代码示例,并结合仓库内的示例源码(docs_src/ 目录)与核心实现(fastapi/ 目录)给出佐证。

配方 1:过滤响应数据——安全底线

问题:如何确保 API 不会返回比预期更多的数据?

做法:使用返回类型注解(return type)或 response_model 声明响应模型,FastAPI 会把输出数据限制并过滤到声明的字段范围内。官方指向 Response Model - Return Type 章节。

一个典型的“输入模型含密码、输出模型不含密码”的例子来自 示例源码

from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user

即使 path operation 函数 实际 return user 返回了带密码的 UserIn 实例,FastAPI 也会用 response_model=UserOut 过滤掉 password 字段。原文档强调这是安全层面的关键能力:如果同一个模型被用在返回用户信息的其他接口上,就可能把用户的密码发送给每个客户端——官方文档明确警告,除非你清楚所有风险,否则永远不要以这种方式存储或返回明文密码。

配方 2:优化 JSON 响应性能

问题:返回 JSON 数据时如何优化性能?

做法:使用返回类型或响应模型。此时 Pydantic 会在 Rust 侧完成到 JSON 的序列化,无需经过 Python 层,因此会快得多(详见 Response Model 文档)。这一点与配方 1 是同一机制的两个收益:既保证了输出的安全过滤,又获得了高性能的序列化路径。

与之配套的还有几个常用变体(同样出自 Response Model 文档,示例源码在 docs_src/response_model/ 目录):

  • 同时声明返回类型与 response_model 时,response_model 优先;可以把函数返回类型标为 Any 以通过 mypy 等严格类型检查,同时让 FastAPI 用 response_model 完成文档、验证与过滤;
  • response_model=None 可以禁用某个 path operation 的响应模型生成,例如你返回的是数据库对象或 Responsedict 的 union 等不是有效 Pydantic 字段的类型;
  • response_model_exclude_unset=True / response_model_exclude_defaults=True / response_model_exclude_none=True 用于省略默认值、只输出实际设置的字段(适合字段很多的 NoSQL 模型,避免返回冗长的全默认值 JSON);
  • response_model_include / response_model_exclude 接收 set[str] 字段名集合,做快速的字段级取舍——但官方提示,此时 OpenAPI 中的 JSON Schema 仍会是完整模型的 Schema,因此更推荐使用多个 Pydantic 类(如 UserIn/UserOut)来表达输入输出的差异。

配方 3:为 API 添加文档 Tags——OpenAPI

问题:如何给 path operations 打标签并在文档 UI 中分组?

做法:给 path operation 装饰器tags 参数,取值为 list[str](通常只是一个 str)。官方指向 Path Operation Configurations - Tags

示例源码 展示了按资源分组的最常见写法:

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/", tags=["items"])
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/", tags=["items"])
async def read_items():
    return [{"name": "Foo", "price": 42}]


@app.get("/users/", tags=["users"])
async def read_users():
    return [{"username": "johndoe"}]

这些 tags 会被写入 OpenAPI schema,并被自动生成的文档界面用于分组展示。应用较大时容易积累大量 tags,官方还建议把 tag 存入 Enum 以保证相关接口始终使用同一个标签名(见 Tags with Enums 小节,示例 tutorial002b_py310.py)。另外别忘了:这些参数是传给装饰器的(@app.get(...) 等),而不是你的 path operation 函数

配方 4:Summary 与 Description——OpenAPI

问题:如何给 path operations 添加摘要和描述,并显示在文档 UI 中?

做法:给装饰器传 summarydescription 参数。示例来自 示例源码

@app.post(
    "/items/",
    summary="Create an item",
    description="Create an item with all the information, name, description, price, tax and a set of unique tags",
)
async def create_item(item: Item) -> Item:
    return item

补充一个官方文档中的进阶技巧:由于描述往往较长,可以写在函数的 docstring 里,FastAPI 会自动读取,并且支持在其中书写 Markdown(详见 Description from docstring 小节)。

配方 5:Response Description——OpenAPI

问题:如何定义文档 UI 中显示的“响应描述”?

做法:使用装饰器参数 response_description。注意区分:response_description 特指响应的描述,而 description 指的是 path operation 整体的描述。OpenAPI 规范要求每个 path operation 必须有响应描述,如果你不提供,FastAPI 会自动生成一句 "Successful response"(详见 Response description 小节,示例 tutorial005_py310.py)。

配方 6:弃用(Deprecate)一个 path operation

问题:如何标记某个 path operation 为已弃用但暂不删除?

做法:给装饰器传 deprecated=True。它会在交互式文档中被明确标记为弃用。示例源码/elements/ 接口与普通的 /items//users/ 形成对照:

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/", tags=["items"])
async def read_items():
    return [{"name": "Foo", "price": 42}]


@app.get("/users/", tags=["users"])
async def read_users():
    return [{"username": "johndoe"}]


@app.get("/elements/", tags=["items"], deprecated=True)
async def read_elements():
    return [{"item_id": "Foo"}]

详见 Deprecate a path operation 小节。

配方 7:把任意数据转换为 JSON 兼容结构

问题:如何把任意数据类型(如 Pydantic 模型)转换成 JSON 兼容的结构(如 dictlist),例如存入只接受 JSON 兼容数据的数据库?

做法:使用 FastAPI 提供的 jsonable_encoder() 函数。官方指向 JSON Compatible Encoder 章节。

典型场景是数据库只接受 JSON 兼容数据:datetime 对象不兼容 JSON,需要转成 ISO 格式的 str;Pydantic 模型(带属性的对象)也不行,只能收 dict示例源码 完整演示:

from datetime import datetime

from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel

fake_db = {}


class Item(BaseModel):
    title: str
    timestamp: datetime
    description: str | None = None


app = FastAPI()


@app.put("/items/{id}")
def update_item(id: str, item: Item):
    json_compatible_item_data = jsonable_encoder(item)
    fake_db[id] = json_compatible_item_data

jsonable_encoder 接收一个对象(如 Pydantic 模型),返回其 JSON 兼容版本:把模型转成 dict、把 datetime 转成 str。需要特别注意它的返回不是一个包含 JSON 文本的大字符串,而是可以用 Python 标准库 json.dumps() 编码的普通数据结构。

从源码层面看,该函数定义在 fastapi/encoders.py#L129。官方文档还特别指出:jsonable_encoder 实际上被 FastAPI 内部用于数据转换——你在响应序列化等场景中享受到的类型兼容能力,底层就来自这一机制,而把它单独暴露出来正是为了让数据库存储等非路由场景也能复用。

配方 8:OpenAPI 元数据——文档信息

问题:如何给 OpenAPI schema 添加 API 标题、摘要、描述、版本、服务条款、联系人、许可证等元数据?

做法:在 FastAPI() 构造时设置相应字段,它们会用于 OpenAPI 规范与自动 API 文档 UI。官方指向 Metadata and Docs URLs 章节。参数说明如下:

参数 类型 说明
title str API 标题。
summary str API 的简短摘要。OpenAPI 3.1.0 / FastAPI 0.99.0 起可用
description str API 的简短描述,支持 Markdown。
version str API 的版本,是你自己应用的版本而非 OpenAPI 的版本,例如 2.5.0
terms_of_service str API 服务条款 URL,若提供必须是 URL。
contact dict 联系人信息,可含 name(联系人/组织名称)、url(URL 格式)、email(邮箱格式)三个字段。
license_info dict 许可证信息,可含 name(设置 license_info 时必填)、url(许可证 URL)、identifierSPDX 许可证表达式,与 url 互斥;OpenAPI 3.1.0 / FastAPI 0.99.0 起可用)。

完整示例

from fastapi import FastAPI

description = """
ChimichangApp API helps you do awesome stuff. 🚀

## Items

You can **read items**.

## Users

You will be able to:

* **Create users** (_not implemented_).
* **Read users** (_not implemented_).
"""

app = FastAPI(
    title="ChimichangApp",
    description=description,
    summary="Deadpool's favorite app. Nuff said.",
    version="0.0.1",
    terms_of_service="http://example.com/terms/",
    contact={
        "name": "Deadpoolio the Amazing",
        "url": "http://x-force.example.com/contact/",
        "email": "dp@x-force.example.com",
    },
    license_info={
        "name": "Apache 2.0",
        "url": "https://www.apache.org/licenses/LICENSE-2.0.html",
    },
)

两个补充点:

  • description 字段中可以直接写 Markdown,会在文档输出中被渲染(如上例中的加粗与斜体);
  • 自 OpenAPI 3.1.0 与 FastAPI 0.99.0 起,license_info 还可以用 identifier(SPDX 表达式)代替 url,参见 License identifier 小节与 示例源码

同章节还介绍了 openapi_tags 参数:为一个列表,每个元素是对应一个 tag 的字典,可包含 name(必填,须与 path operations / APIRoutertags 参数里的标签名一致)、description(支持 Markdown,会显示在文档 UI 中)、externalDocs(含 description 与必填的 url)。元数据字典在列表中的顺序决定标签在文档 UI 中的显示顺序——不要求为所有 tag 都添加元数据(见 示例源码)。

配方 9:自定义 OpenAPI URL(或移除)

问题:如何自定义 OpenAPI schema 的服务地址,或彻底关闭它?

做法:默认 OpenAPI schema 服务在 /openapi.json,可用 FastAPI()openapi_url 参数定制。示例源码

from fastapi import FastAPI

app = FastAPI(openapi_url="/api/v1/openapi.json")


@app.get("/items/")
async def read_items():
    return [{"name": "Foo"}]

若要完全禁用 OpenAPI schema,可设置 openapi_url=None——这会同时禁用依赖它的文档用户界面(Swagger UI 与 ReDoc)。这些参数由 FastAPI 类在 fastapi/applications.py 中接收并用于构建 OpenAPI 路由与文档路由。

配方 10:自定义文档界面 URL

问题:如何修改自动生成的文档用户界面所用的 URL?

做法:两个内置文档界面分别是:

  • Swagger UI:默认服务在 /docs,用 docs_url 参数设置 URL,设 docs_url=None 可禁用;
  • ReDoc:默认服务在 /redoc,用 redoc_url 参数设置 URL,设 redoc_url=None 可禁用。

示例源码 把 Swagger UI 改到 /documentation 并禁用 ReDoc:

from fastapi import FastAPI

app = FastAPI(docs_url="/documentation", redoc_url=None)


@app.get("/items/")
async def read_items():
    return [{"name": "Foo"}]

快速索引:General Recipes 全条目一览

通用问题 对应配方 详细文档
过滤数据、防止返回敏感信息(安全) 返回类型 / response_model Response Model - Return Type
优化返回 JSON 的性能 返回类型 / 响应模型(Pydantic Rust 序列化) Response Model - Return Type
文档 Tags 分组 tags 装饰器参数 Path Operation Configuration - Tags
Summary 与 Description summary / description 参数(或 docstring) Path Operation Configuration - Summary and Description
响应描述 response_description 参数 Path Operation Configuration - Response description
弃用 path operation deprecated=True 参数 Path Operation Configuration - Deprecation
任意数据转 JSON 兼容 jsonable_encoder() JSON Compatible Encoder
OpenAPI 元数据(license、version、contact 等) FastAPI() 元数据参数 Metadata and Docs URLs
自定义 / 关闭 OpenAPI URL openapi_urlNone 可关闭) Metadata and Docs URLs - OpenAPI URL
自定义文档界面 URL docs_url / redoc_url Metadata and Docs URLs - Docs URLs

以上配方均来自仓库内真实可运行的示例代码(docs_src/ 下对应文件)与官方教程文档,可直接复制到你的项目中按需裁剪。如需结构化地学习 FastAPI,建议按 Tutorial - User Guide 逐章阅读,而把本文当作日常开发中的速查手册。

登录后查看全文
热门项目推荐
相关项目推荐