ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FastAPI 中的 OpenAPI Callbacks:用 `callbacks` 参数自动文档化外部回调 API

FastAPI 中的 OpenAPI Callbacks:用 `callbacks` 参数自动文档化外部回调 API FastAPI 中的 OpenAPI Callbacks用callbacks参数自动文档化外部回调 API【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi本文围绕 FastAPI 官方教程docs/de/docs/advanced/openapi-callbacks.mdOpenAPI-Callbacks展开当你的 API 在处理请求后会反过来调用外部开发者的 API即回调时如何用一个APIRouter加上路径操作装饰器的callbacks参数把这条回调契约完整写入 OpenAPI 规范并自动展示在 Swagger UI 的 Callbacks 标签页中。读完后你将能够定义带回调文档的 FastAPI 应用、使用 OpenAPI 3 表达式让回调路径动态引用原始请求中的参数与 Body 字段并在/docs中验证外部开发者应实现的接口形态。什么是 OpenAPI Callbacks先理解回调场景你可以构建一种 API其中某个路径操作path operation在处理过程中会触发对外部 API的请求——这个外部 API 由别人创建通常正是那个正在使用你 API 的开发者。这个过程被称为Callback回调外部开发者编写的软件先向你的 API 发送请求随后你的 API 再回拨calls back向该外部 API 发送一个请求。此时你往往希望文档化这条外部 API 应有的样子它应包含哪个路径操作哪个方法、哪个路径它应接收什么样的请求 Body它应返回什么样的响应。FastAPI 借助 OpenAPI 规范原生的callbacks字段让你复用写 FastAPI 路径操作的全部经验来描述这条外部 API——包括参数声明、Pydantic 请求体模型和response_model。示例场景一个带回调的发票应用用一个具体例子贯穿全文假设你开发了一个发票创建应用。每张发票包含id、title可选、customer、total。你的 API 使用者一个外部开发者通过 POST 请求在你的 API 中创建一张发票。随后你的 API假设性地会把发票发送给该外部开发者的某个客户收齐款项向 API 使用者外部开发者发回一条通知——这一步是通过你的 API 向外部开发者提供的外部 API 发送一个 POST 请求实现的这就是回调。下面的教程代码位于 docs_src/openapi_callbacks/tutorial001_py310.py完整文件仅 51 行本文会逐段讲解。普通的 FastAPI 应用部分先看在加入回调之前常规 API 应用长什么样。它有一个路径操作接收Invoice请求体并带一个携带回调 URL 的查询参数callback_urlfrom fastapi import APIRouter, FastAPI from pydantic import BaseModel, HttpUrl app FastAPI() class Invoice(BaseModel): id: str title: str | None None customer: str total: floatapp.post(/invoices/, callbacksinvoices_callback_router.routes) def create_invoice(invoice: Invoice, callback_url: HttpUrl | None None): Create an invoice. ... # Send the invoice, collect the money, send the notification (the callback) return {msg: Invoice received}这里有一个值得注意的细节callback_url查询参数使用了 Pydantic 的HttpUrl类型见 docs_src/openapi_callbacks/tutorial001_py310.py。从生成的 OpenAPI 测试快照可以看到该参数被渲染为format: uri、minLength: 1、maxLength: 2083的字符串 schema且因HttpUrl | None而变为可选required: False见 tests/test_sub_callbacks.py。上面代码中唯一新的东西是传给路径操作装饰器的参数callbacksinvoices_callback_router.routes下面详解。文档化回调本身真正的回调代码有多简单实际的回调实现代码强烈依赖于你自己的业务因应用而异可能只是短短一两行例如callback_url https://example.com/api/v1/invoices/events/ httpx.post(callback_url, json{description: Invoice paid, paid: True})但回调中最关键的部分是确保你的 API 使用者外部开发者正确实现了那条外部 API——按照你的 API 将在回调请求体中发送的数据格式来实现。本教程示例不实现回调本身它可能只有一行代码只演示文档化的部分。提示实际的回调本质上就是一个 HTTP 请求。实现时可以使用httpx、requests等任意 HTTP 客户端库。这一点也被 FastAPI 源码的官方文档字符串明确确认callbacks参数的 Doc 写着 List ofpath operationsthat will be used as OpenAPI callbacks.This is only for OpenAPI documentation, the callbacks wont be used directly.It will be added to the generated OpenAPI (e.g. visible at/docs)见 fastapi/applications.py 中include_router的callbacks参数说明。也就是说回调路由永远不会被你的应用执行它们只用于生成 OpenAPI 文档。编写回调文档代码把自己想象成外部开发者用来文档化回调的代码不会在你的应用中执行你只是需要它来描述那条外部 API 应长什么样。但你已经知道如何用 FastAPI 轻松创建自动文档——于是用同样的方法把外部 API 应实现的路径操作写出来即可。提示编写回调文档代码时不妨想象自己就是那个外部开发者此刻正在实现的不是你的 API而是外部 API。暂时切换到这个视角后参数放在哪里、Body 用哪个 Pydantic 模型、Response 是什么都会变得直观。第 1 步创建一个回调APIRouter先新建一个APIRouter用来装一个或多个回调from fastapi import APIRouter, FastAPI invoices_callback_router APIRouter()见 docs_src/openapi_callbacks/tutorial001_py310.py。第 2 步创建回调路径操作使用上面创建的APIRouter来定义回调路径操作它看起来就像一条普通的 FastAPI路径操作声明它应接收的 Body如body: InvoiceEvent可以声明它应返回的响应如response_modelInvoiceEventReceivedclass InvoiceEvent(BaseModel): description: str paid: bool class InvoiceEventReceived(BaseModel): ok: bool invoices_callback_router APIRouter() invoices_callback_router.post( {$callback_url}/invoices/{$request.body.id}, response_modelInvoiceEventReceived ) def invoice_notification(body: InvoiceEvent): pass见 docs_src/openapi_callbacks/tutorial001_py310.py。与普通路径操作相比有两个主要区别函数体不需要真实代码因为你的应用永远不会调用它它只用于文档化外部 API所以函数体可以只有pass。路径可以包含 OpenAPI 3 表达式可以引用发送到你 API 的原始请求中的变量参数和请求体部分。回调路径表达式OpenAPI 3 expression回调路径可以是一个OpenAPI 3 表达式str字符串其中可以内嵌对原始请求内容的引用。本例中是{$callback_url}/invoices/{$request.body.id}表达式的语义{$callback_url}取自原始请求的查询参数callback_url{$request.body.id}取自原始请求 JSON Body 中的id字段。完整走一遍数据流外部开发者向你的 API发送请求https://yourapi.com/invoices/?callback_urlhttps://www.external.org/eventsJSON Body 为{ id: 2expen51ve, customer: Mr. Richie Rich, total: 9999 }你的 API 处理完发票后在某个时刻会向callback_url即外部 API发送回调请求https://www.external.org/events/invoices/2expen51ve回调的 JSON Body 大致为{ description: Payment celebration, paid: true }并期望从该外部 API收到如下 JSON 响应{ ok: true }注意最终使用的回调 URL 同时包含了两处信息——作为查询参数传入的callback_urlhttps://www.external.org/events和 JSON Body 中的发票id2expen51ve。这正是 OpenAPI 表达式相对静态路径的价值所在。第 3 步把回调 Router 挂到装饰器上此时所需的回调路径操作即外部开发者应在外部 API中实现的接口已经放在回调 Router 里。现在在你的API 的路径操作装饰器上通过callbacks参数传入该回调 Router 的.routes属性app.post(/invoices/, callbacksinvoices_callback_router.routes) def create_invoice(invoice: Invoice, callback_url: HttpUrl | None None): ...见 docs_src/openapi_callbacks/tutorial001_py310.py。提示传给callbacks的不是 Router 本身invoices_callback_router而是它的.routes属性即invoices_callback_router.routes。FastAPI 会用这些路由来生成回调的 OpenAPI 文档。从源码看callbacks的类型就是list[BaseRoute] | None在路由初始化时被原样存储到路由对象上见 fastapi/routing.py 中_populate_api_route_state的callbacks参数与 fastapi/routing.py 的route.callbacks callbacks。回调如何被写入 OpenAPI源码视角OpenAPI 生成时FastAPI 遍历route.callbacks对每条APIRoute递归生成完整的 operation并以回调函数名为键组织成callbacks字典挂到对应 operation 下if route.callbacks: callbacks {} for callback in route.callbacks: if isinstance(callback, routing.APIRoute): ( cb_path, cb_security_schemes, cb_definitions, ) get_openapi_path(route..., ...) callbacks[callback.name] {callback.path: cb_path} operation[callbacks] callbacks见 fastapi/openapi/utils.py。这解释了两件事回调 operation 会像普通操作一样生成operationId、requestBody、responses且回调中引用的 Pydantic 模型InvoiceEvent、InvoiceEventReceived也会进入components/schemas该处同时收集回调路由的模型定义见 fastapi/openapi/utils.py 的get_fields_from_routes(api_route.callbacks)回调的键是回调函数的name如invoice_notification值是以表达式路径字符串{$callback_url}/invoices/{$request.body.id}注意不是编译后的正则而是你写的原始字符串为键的 PathItem。测试快照完整印证了这段实现在 tests/test_sub_callbacks.py 中/invoices/的 POST operation 下生成了callbacks对象包含event_callbackGET表达式{$callback_url}/events/{$request.body.title}与invoice_notificationPOST表达式{$callback_url}/invoices/{$request.body.id}两个回调且requestBody分别引用#/components/schemas/Event与#/components/schemas/InvoiceEvent。进阶include_router也可以附加回调除了逐条挂在路径操作装饰器上app.include_router(...)和APIRouter本身也接受callbacks参数可为 Router 内的所有路径操作附加回调文档源码 Doc 说明为 OpenAPI callbacks that should apply to allpath operationsin this router见 fastapi/routing.py 中APIRouter.include_router的参数定义。上文的 tests/test_sub_callbacks.py 正是这个用法POST /invoices/自带callbacksinvoices_callback_router.routes而app.include_router(subrouter, callbacksevents_callback_router.routes)又追加了一个event_callback——两个来源的回调最终合并出现在同一 operation 的callbacks中。从源码结构看_RouterIncludeContext在 include 链路上会持续合并父级与子级的 callbacks见 fastapi/routing.py 的callbacks: list[BaseRoute]字段及 fastapi/routing.py 的合并逻辑。在/docs中验证启动应用并访问http://127.0.0.1:8000/docs你会看到 Swagger UI 中该路径操作多出一个Callbacks标签页展示外部 API应有的样子从截图中可以看到Callbacks 区块以回调函数名invoice_notification为标题方法为POST路径显示为表达式原文{$callback_url}/invoices/{$request.body.id}Request body标记为 required内容为InvoiceEvent的示例值description: string、paid: trueResponses列出 200 等状态码。这正是给外部开发者看的契约照着这个结构实现一个接收InvoiceEvent并返回InvoiceEventReceived的接口即可正确接收你的回调。小结关键要点回顾要点说明依据callbacks参数传入list[BaseRoute]通常为某callback_router.routes而非 Router 本身fastapi/routing.py、docs_src/openapi_callbacks/tutorial001_py310.py回调只为文档回调路径操作不会被应用执行仅用于生成 OpenAPI 文档函数体可passfastapi/applications.py表达式路径回调路径可用{$参数名}与{$request.body.字段}引用原始请求fastapi/openapi/utils.py、tests/test_sub_callbacks.py挂接位置路径操作装饰器app.post(..., callbacks...)与include_router(..., callbacks...)均可fastapi/routing.pycallback_url类型用 PydanticHttpUrl声明查询参数OpenAPI 中渲染为format: uri且可选tests/test_sub_callbacks.py验证方式访问/docs查看 Callbacks 标签页或对比/openapi.json中 operation 的callbacks字段tests/test_sub_callbacks.py参考文件教程文档 docs/de/docs/advanced/openapi-callbacks.md、示例代码 docs_src/openapi_callbacks/tutorial001_py310.py、核心实现 fastapi/openapi/utils.py 与 fastapi/routing.py、测试 tests/test_sub_callbacks.py。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表