扩展 OpenAPI¶
警告
本章介绍的功能较难,您可以跳过阅读。
如果您刚开始学习用户指南,最好跳过本章。
如果您确定要修改 OpenAPI 概图,请继续阅读。
某些情况下,我们需要修改 OpenAPI 概图。
本章介绍如何修改 OpenAPI 概图。
常规流程¶
常规(默认)流程如下。
FastAPI
应用(实例)提供了返回 OpenAPI 概图的 .openapi()
方法。
作为应用对象创建的组成部分,要注册 /openapi.json
(或其他为 openapi_url
设置的任意内容)路径操作。
它只返回包含应用的 .openapi()
方法操作结果的 JSON 响应。
但默认情况下,.openapi()
只是检查 .openapi_schema
属性是否包含内容,并返回其中的内容。
如果 .openapi_schema
属性没有内容,该方法就使用 fastapi.openapi.utils.get_openapi
工具函数生成内容。
get_openapi()
函数接收如下参数:
title
:文档中显示的 OpenAPI 标题version
:API 的版本号,例如2.5.0
openapi_version
: OpenAPI 规范的版本号,默认为最新版:3.0.2
description
:API 的描述说明routes
:路由列表,每个路由都是注册的路径操作。这些路由是从app.routes
中提取的。
覆盖默认值¶
get_openapi()
工具函数还可以用于生成 OpenAPI 概图,并利用上述信息参数覆盖指定的内容。
例如,使用 ReDoc 的 OpenAPI 扩展添加自定义 Logo。
常规 FastAPI¶
首先,编写常规 FastAPI 应用:
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
app = FastAPI()
@app.get("/items/")
async def read_items():
return [{"name": "Foo"}]
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Custom title",
version="2.5.0",
description="This is a very custom OpenAPI schema",
routes=app.routes,
)
openapi_schema["info"]["x-logo"] = {
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
}
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
生成 OpenAPI 概图¶
然后,在 custom_openapi()
函数里使用 get_openapi()
工具函数生成 OpenAPI 概图:
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
app = FastAPI()
@app.get("/items/")
async def read_items():
return [{"name": "Foo"}]
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Custom title",
version="2.5.0",
description="This is a very custom OpenAPI schema",
routes=app.routes,
)
openapi_schema["info"]["x-logo"] = {
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
}
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
修改 OpenAPI 概图¶
添加 ReDoc 扩展信息,为 OpenAPI 概图里的 info
对象添加自定义 x-logo
:
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
app = FastAPI()
@app.get("/items/")
async def read_items():
return [{"name": "Foo"}]
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Custom title",
version="2.5.0",
description="This is a very custom OpenAPI schema",
routes=app.routes,
)
openapi_schema["info"]["x-logo"] = {
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
}
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
缓存 OpenAPI 概图¶
把 .openapi_schema
属性当作缓存,存储生成的概图。
通过这种方式,FastAPI 应用不必在用户每次打开 API 文档时反复生成概图。
只需生成一次,下次请求时就可以使用缓存的概图。
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
app = FastAPI()
@app.get("/items/")
async def read_items():
return [{"name": "Foo"}]
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Custom title",
version="2.5.0",
description="This is a very custom OpenAPI schema",
routes=app.routes,
)
openapi_schema["info"]["x-logo"] = {
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
}
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
覆盖方法¶
用新函数替换 .openapi()
方法。
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
app = FastAPI()
@app.get("/items/")
async def read_items():
return [{"name": "Foo"}]
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Custom title",
version="2.5.0",
description="This is a very custom OpenAPI schema",
routes=app.routes,
)
openapi_schema["info"]["x-logo"] = {
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
}
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
查看文档¶
打开 http://127.0.0.1:8000/redoc,查看自定义 Logo(本例中是 FastAPI 的 Logo):
文档 JavaScript 与 CSS 自托管¶
FastAPI 内置了 Swagger UI 和 ReDoc 文档,这两种文档都需要调用 JavaScript 与 CSS 文件。
这些文件默认由 CDN 提供支持服务。
但也可以自定义设置指定的 CDN 或自行提供文件服务。
这种做法很常用,例如,在没有联网或本地局域网时也能让应用在离线状态下正常运行。
本文介绍如何为 FastAPI 应用提供文件自托管服务,并设置文档使用这些文件。
项目文件架构¶
假设项目文件架构如下:
.
├── app
│ ├── __init__.py
│ ├── main.py
接下来,创建存储静态文件的文件夹。
新的文件架构如下:
.
├── app
│ ├── __init__.py
│ ├── main.py
└── static/
下载文件¶
下载文档所需的静态文件,把文件放到 static/
文件夹里。
右键点击链接,选择另存为...。
Swagger UI 使用如下文件:
ReDoc 使用如下文件:
保存好后,文件架构所示如下:
.
├── app
│ ├── __init__.py
│ ├── main.py
└── static
├── redoc.standalone.js
├── swagger-ui-bundle.js
└── swagger-ui.css
安装 aiofiles
¶
现在,安装 aiofiles
:
$ pip install aiofiles
---> 100%
静态文件服务¶
- 导入
StaticFiles
- 在指定路径下挂载
StaticFiles()
实例
from fastapi import FastAPI
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
from fastapi.staticfiles import StaticFiles
app = FastAPI(docs_url=None, redoc_url=None)
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/swagger-ui-bundle.js",
swagger_css_url="/static/swagger-ui.css",
)
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
redoc_js_url="/static/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
测试静态文件¶
启动应用,打开 http://127.0.0.1:8000/static/redoc.standalone.js。
就能看到 ReDoc 的 JavaScript 文件。
该文件开头如下:
/*!
* ReDoc - OpenAPI/Swagger-generated API Reference Documentation
* -------------------------------------------------------------
* Version: "2.0.0-rc.18"
* Repo: https://github.com/Redocly/redoc
*/
!function(e,t){"object"==typeof exports&&"object"==typeof m
...
能打开这个文件就表示 FastAPI 应用能提供静态文件服务,并且文档要调用的静态文件放到了正确的位置。
接下来,使用静态文件配置文档。
禁用 API 文档¶
第一步是禁用 API 文档,就是使用 CDN 的默认文档。
创建 FastAPI
应用时把文档的 URL 设置为 None
即可禁用默认文档:
from fastapi import FastAPI
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
from fastapi.staticfiles import StaticFiles
app = FastAPI(docs_url=None, redoc_url=None)
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/swagger-ui-bundle.js",
swagger_css_url="/static/swagger-ui.css",
)
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
redoc_js_url="/static/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
添加自定义文档¶
现在,创建自定义文档的路径操作。
导入 FastAPI 内部函数为文档创建 HTML 页面,并把所需参数传递给这些函数:
openapi_url
: API 文档获取 OpenAPI 概图的 HTML 页面,此处可使用app.openapi_url
title
:API 的标题oauth2_redirect_url
:此处使用app.swagger_ui_oauth2_redirect_url
作为默认值swagger_js_url
:Swagger UI 文档所需 JavaScript 文件的 URL,即为应用提供服务的文件swagger_css_url
:Swagger UI 文档所需 CSS 文件的 URL,即为应用提供服务的文件
添加 ReDoc 文档的方式与此类似……
from fastapi import FastAPI
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
from fastapi.staticfiles import StaticFiles
app = FastAPI(docs_url=None, redoc_url=None)
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/swagger-ui-bundle.js",
swagger_css_url="/static/swagger-ui.css",
)
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
redoc_js_url="/static/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
提示
swagger_ui_redirect
的路径操作是 OAuth2 的辅助函数。
集成 API 与 OAuth2 第三方应用时,您能进行身份验证,使用请求凭证返回 API 文档,并使用真正的 OAuth2 身份验证与 API 文档进行交互操作。
Swagger UI 在后台进行处理,但它需要这个重定向辅助函数。
创建测试路径操作¶
现在,测试各项功能是否能顺利运行。创建路径操作:
from fastapi import FastAPI
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
from fastapi.staticfiles import StaticFiles
app = FastAPI(docs_url=None, redoc_url=None)
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/swagger-ui-bundle.js",
swagger_css_url="/static/swagger-ui.css",
)
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
redoc_js_url="/static/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
测试文档¶
断开 WiFi 连接,打开 http://127.0.0.1:8000/docs,刷新页面。
现在,就算没有联网也能查看并操作 API 文档。