FastAPI:(13)后台任务,元数据,文档URL

FastAPI:(13)后台任务,元数据,文档URL

由于优快云无法展示「渐构」的「#d,#e,#t,#c,#v,#a」标签,推荐访问我个人网站进行阅读:Hkini
「渐构展示」如下:在这里插入图片描述
在这里插入图片描述

#c 概述 文章内容概述

FastAPI高级功能
后台任务
元数据
文档URL
异步执行
非阻塞
邮件发送
日志记录
即时响应
文档增强
分类组织
接口描述
标签分组
自定义路径
禁用文档
Swagger UI
ReDoc

1.后台任务

#d 后台任务

后台任务(Background Task)是FastAPI提供的功能,可以让一些耗时的任务在后端异步执行,而不需要阻塞主线程的请求响应流程。这类任务通常用于处理非即时响应的操作,如发送邮件、数据分析、日志记录、定时任务等。后台任务的执行是非阻塞的,这意味着它们不会影响到用户的请求响应速度。

重要特征:

  • 异步执行:后台任务在后台线程中运行,而不阻塞主线程,从而保证了主线程的响应性能。
  • 非阻塞性:后台任务的运行不会影响客户端的请求和响应过程。
  • 适用于耗时任务:例如邮件发送、数据处理、文件上传等,这些任务通常需要较长的时间来完成,但并不需要立即返回结果。
  • 可通过 BackgroundTasks 提供:FastAPI提供的 BackgroundTasks 类可以用于启动这些任务。

#e 发送电子邮件(正例) 后台任务

假设一个电子商务平台,在用户下单成功后,系统需要向用户发送订单确认邮件。由于邮件发送是一个网络请求,且可能需要较长时间,所以最好将它放入后台任务中。

特征对比:

  • 异步执行:后台任务 send_email 是在主线程外执行的,主线程不会等待邮件发送完成。
  • 非阻塞性:请求返回立即响应,邮件发送任务在后台处理,不会阻塞主线程。
  • 适用于耗时任务:邮件发送的过程需要一定的时间,适合使用后台任务来处理。
  • 通过 BackgroundTasks 提供:通过使用 background_tasks.add_task() 启动后台任务。
from fastapi import BackgroundTasks, FastAPI # 导入BackgroundTasks

app = FastAPI()


def write_notification(email: str, message=""): # 创建后台运行的函数,只是一个可以接收参数的「标准函数」
# 由于写入操作不使用 `async` 和 `await`,因此使用普通的 `def` 定义函数
    with open("log.txt", mode="w") as email_file:
        content = f"notification for {email}: {message}"
        email_file.write(content)


@app.post("/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
    background_tasks.add_task(write_notification, email, message="some notification")
    # 使用 `.add_task()` 方法将「任务函数」传递给「后台任务」对象
    return {"message": "Notification sent in the background"}

.add_task() 接收以下参数

  • 要在后台运行的任务函数(write_notification)。
  • 应按顺序传递给任务函数的任何参数序列(email)。
  • 应传递给任务函数的任何关键字参数(message="some notification")。

#e 记录访问日志(正例) 后台任务

在用户访问某个资源后,为了性能优化,不立即将日志写入磁盘,而是使用后台任务异步地将访问记录写入日志文件中。

特征对比:

  • 异步非阻塞:访问日志在主响应之后记录,不影响资源返回速度。
  • 传参灵活性:路径参数 /resource/ 成功传入任务函数。
  • 非实时性任务:日志写入可以延后进行,对主业务没有依赖。
from fastapi import FastAPI, BackgroundTasks
from datetime import datetime

app = FastAPI()

def log_access(path: str):
    with open("access.log", "a") as f:
        f.write(f"{datetime.now()} - Path Accessed: {path}\n")

@app.get("/resource/")
async def access_resource(background_tasks: BackgroundTasks):
    background_tasks.add_task(log_access, "/resource/")
    return {"message": "资源访问成功"}

#e 查询数据库并返回(反例) 后台任务

在用户请求中,通过后台任务查询数据库,并想将结果返回给用户。由于后台任务在响应返回之后才执行,这会导致主响应时查询结果尚未完成,用户无法获取所需数据。

特征对比:

  • 异步非阻塞:虽然任务异步执行,但主响应时数据尚未查询完成,用户无法获得期望的查询结果。
  • 非实时性任务误用:此操作本应为实时任务,强依赖查询结果却被放入后台,造成逻辑错误。
  • 自动调度但目的错误:后台任务功能被滥用为主业务的一部分,而非附加操作。
from fastapi import FastAPI, BackgroundTasks

app = FastAPI()

user_data = {}

def query_user_data(user_id: str):
    # 模拟数据库查询
    user_data[user_id] = {"name": "Alice", "age": 30}

@app.get("/get_user/")
async def get_user(user_id: str, background_tasks: BackgroundTasks):
    background_tasks.add_task(query_user_data, user_id)
    return {"message": "用户数据查询中", "data": user_data.get(user_id)}

#e 依赖注入(正例) 后台任务

使用 BackgroundTasks 也适用于依赖注入系统,可以在多个级别声明类型为 BackgroundTasks 的参数:在「路径操作函数」中,在依赖项(可依赖项)中,在子依赖项中,等等。

FastAPI 知道在每种情况下该做什么以及如何重用同一个对象,以便所有后台任务都合并在一起并在之后在后台运行

在此示例中,「消息将在发送响应后」写入 log.txt 文件。如果请求中存在查询,它将在后台任务中写入日志。然后,在「路径操作函数」中生成的另一个后台任务将使用 email 路径参数写入消息。

from typing import Annotated

from fastapi import BackgroundTasks, Depends, FastAPI

app = FastAPI()


def write_log(message: str):
    with open("log.txt", mode="a") as log:
        log.write(message)


def get_query(background_tasks: BackgroundTasks, q: str | None = None):
    if q:
        message = f"found query: {q}\n"
        background_tasks.add_task(write_log, message)
    return q


@app.post("/send-notification/{email}")
async def send_notification(
    email: str, background_tasks: BackgroundTasks, q: Annotated[str, Depends(get_query)]
):
    message = f"message to {email}\n"
    background_tasks.add_task(write_log, message)
    return {"message": "Message sent"}

#c 细节 技术细节

BackgroundTasks 直接来自 starlette.background

它被直接导入/包含到 FastAPI 中,以便可以从fastapi中导入它,并避免意外地从starlette.background中导入备用的BackgroundTask(末尾没有“s”)。

通过仅使用BackgroundTasks(而不是BackgroundTask),就可以将其用作「路径操作函数」参数,并让FastAPI为您处理其余部分,就像直接使用Request对象一样。

仍然可以在 FastAPI 中单独使用BackgroundTask,但是必须在代码中创建对象并返回包含它的 Starlette Response

可以在Starlette 的背景任务官方文档中查看更多详细信息。

#c 提醒 注意事项

如果需要执行繁重的后台计算,并且不一定需要由同一个进程运行(例如,不需要共享内存、变量等),那么可能受益于使用其他更大的工具,例如Celery

它们往往需要更复杂的配置,一个消息/作业队列管理器,如 RabbitMQ 或 Redis,但它们允许在多个进程中运行后台任务,尤其是在多个服务器中。

要查看示例,请查看项目生成器,它们都已包含已配置的 Celery。

但是,如果需要访问来自同一个FastAPI应用程序的变量和对象,或者需要执行小的后台任务(例如发送电子邮件通知),可以简单地使用BackgroundTasks

2.元数据

#d 元数据

“元数据”是用于补充描述接口信息的辅助数据,不会影响业务逻辑的运行,但会用于 API 文档生成(如 OpenAPI / Swagger UI)以提高可读性、组织性、以及开发者交互体验。元数据常应用于路由分组、接口描述、标签、说明、响应描述等方面。

重要特征:

  • 文档增强性:元数据专为 OpenAPI 文档而设计,帮助自动生成更加清晰、结构化的接口文档。
  • 业务无关性:元数据不参与业务处理或控制流程,只影响文档呈现。
  • 分类组织能力:元数据可以用于给路由分组(如 tags),使接口在 Swagger UI 中分组展示。
  • 增强可读性与交互性:通过 summarydescription 等提升接口含义的表达。
参数类型描述
titlestrAPI 的标题。
summarystrAPI 的简短摘要。 自 OpenAPI 3.1.0、FastAPI 0.99.0 起可用。
descriptionstrAPI 的简短描述。它可以使用 Markdown。
version字符串API 的版本。这是你自己的应用程序的版本,而不是 OpenAPI 的版本。例如 2.5.0
terms_of_servicestrAPI 的服务条款的 URL。如果提供,则必须为 URL。
contactdict公开 API 的联系信息。它可以包含多个字段。
license_infodict公开 API 的许可信息。它可以包含多个字段。

contact字段:

参数类型描述
namestr联系人/组织的标识名称。
urlstr指向联系信息的 URL。必须为 URL 格式。
emailstr联系人/组织的电子邮件地址。必须为电子邮件地址格式。
license_info字段:
参数类型描述
namestr必需(如果设置了 license_info)。用于 API 的许可证名称。
identifierstrAPI 的 SPDX 许可证表达式。identifier 字段与 url 字段互斥。 自 OpenAPI 3.1.0、FastAPI 0.99.0 起可用。
urlstrAPI 使用的许可证的 URL。必须为 URL 格式。

#e 官网例子(正例) 元数据

可以在 description 字段中写入 Markdown,它将在输出中呈现。
自 OpenAPI 3.1.0 和 FastAPI 0.99.0 起,你也可以使用 identifier 而不是 url 设置 license_info

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",
        "identifier": "MIT",
    },
)


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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

#e 标签元数据(正例) 元数据

还可以使用参数 openapi_tags 为用于将路径操作分组的不同标签添加其他元数据。

它接受一个列表,其中包含每个标签的字典。

每个字典可以包含

  • name必需):一个 str,与在「路径操作」和 APIRouter 中的 tags 参数中使用的相同标签名称。
  • description:一个 str,包含标签的简短描述。它可以包含 Markdown,并且将显示在文档 UI 中。
  • externalDocs:一个 dict,描述具有以下内容的外部文档
    • description:一个 str,包含外部文档的简短描述。
    • url必需):一个 str,包含外部文档的 URL。

使用 usersitems 标签的示例来实现这一点。为标签创建元数据,并将其传递给 openapi_tags 参数

可以在描述中使用 Markdown,例如“login”将显示为粗体(login),“fancy”将显示为斜体(fancy)。

也无需为使用的所有标签添加元数据。

from fastapi import FastAPI

tags_metadata = [ # 创建标签元数据
    {
        "name": "users",
        "description": "Operations with users. The **login** logic is also here.",
    },
    {
        "name": "items",
        "description": "Manage items. So _fancy_ they have their own docs.",
        "externalDocs": {
            "description": "Items external docs",
            "url": "https://fastapi.org.cn/",
        },
    },
]

app = FastAPI(openapi_tags=tags_metadata)


@app.get("/users/", tags=["users"])
async def get_users():
    return [{"name": "Harry"}, {"name": "Ron"}]


@app.get("/items/", tags=["items"])
async def get_items():
    return [{"name": "wand"}, {"name": "flying broom"}]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.OpenAPI URl

#c 说明 OpenAPI的URL

默认情况下,OpenAPI 模式位于 /openapi.json 中。但可以使用参数 openapi_url 来配置它。
例如,要将其设置为在 /api/v1/openapi.json 中提供服务。
如果要完全禁用 OpenAPI 模式,可以设置 openapi_url=None,这也会禁用使用它的文档用户界面。

from fastapi import FastAPI

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


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

#c 说明 文档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"}]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

remandancy.h

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值