如何将自定义 HTML 内容添加到 FastAPI Swagger UI 文档?

2024-02-15

我需要在 FastAPI 应用程序的 Swagger UI 中添加一个自定义按钮。我发现这个答案 https://stackoverflow.com/questions/74661044/add-a-custom-javascript-to-the-fastapi-swagger-ui-docs-webpage-in-python/75022153#75022153这提出了一个很好的解决方案,将自定义 javascript 添加到 Swagger UI 中这个文档 https://fastapi.tiangolo.com/ru/advanced/extending-openapi/来自 FastAPI。但此解决方案仅适用于添加自定义 JavaScript 代码。我尝试添加一些 HTML 代码,以使用 swagger UI 授权按钮样式向其添加新按钮:

custom_html = '<div class="scheme-containerr"><section class="schemes wrapper block col-12"><div class="auth-wrapper"><button class="btn authorize"><span>Authorize Google</span><svg width="20" height="20"><use href="#unlocked" xlink:href="#unlocked"></use></svg></button></div></section></div>'

@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",
        custom_js_url=google_custom_button,
        custom_html=custom_html,
    )

def get_swagger_ui_html(
        *,
        ...
        custom_html: Optional[str] = None,
) -> HTMLResponse:

    ...

    html = f"""
    <!DOCTYPE html>
    <html>
    <head>
    <link type="text/css" rel="stylesheet" href="{swagger_css_url}">
    <link rel="shortcut icon" href="{swagger_favicon_url}">
    <title>{title}</title>
    </head>
    <body>
    <div id="swagger-ui">
    {custom_html if custom_html else ""}  # <-- I added the HTML code here
    </div>
    """
    ....

但看起来就像我放在中间的任何东西<div id="swagger-ui"></div>以某种方式被覆盖并且不会出现在 Swagger UI 中。

如何使用 FastAPI 在 Swagger UI 中添加自定义 HTML(在本例中为 Swagger 的授权按钮等按钮)以满足特定需求?

Update

如果我在外部添加自定义 HTML<div id="swagger-ui"></div>我可以在 Swagger UI 中看到我的自定义按钮,如下所示:

但我想在原始授权按钮所在的位置添加我的按钮。


你可以修改FastAPI的get_swagger_ui_html() https://github.com/tiangolo/fastapi/blob/1574c9623103d03d27117f64b937d754cba12584/fastapi/openapi/docs.py#L16函数,以注入一些自定义 JavaScript 代码,如 @lunaa 所描述here https://stackoverflow.com/a/75022153/17865804,并通过以下方式以编程方式创建自定义 HTML 按钮custom_script.js。然而,自从Authorize按钮元素是在 DOM/Window 加载后创建的 - 并且似乎没有本地方法可以在定义后运行 JS 代码,即使您使用Window.load https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event事件来运行 JavaScript 代码 - 并且您需要在其旁边添加自定义按钮,您可以使用所描述的方法简单地等待该元素被创建here https://stackoverflow.com/a/61511955,然后创建自定义按钮并将其添加到 DOM。

完整的工作示例

app.py

from fastapi import FastAPI
from fastapi import Depends
from fastapi.security import OpenIdConnect
from fastapi.staticfiles import StaticFiles
from fastapi.openapi.docs import (
    get_redoc_html,
    get_swagger_ui_oauth2_redirect_html,
)
from custom_swagger import get_swagger_ui_html


app = FastAPI(docs_url=None) 
app.mount("/static", StaticFiles(directory="static"), name="static")
oidc_google = OpenIdConnect(openIdConnectUrl='https://accounts.google.com/.well-known/openid-configuration')


@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
    return get_swagger_ui_html(
        openapi_url=app.openapi_url,
        title="My API",
        oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
        #swagger_js_url="/static/swagger-ui-bundle.js",  # Optional
        #swagger_css_url="/static/swagger-ui.css",  # Optional
        #swagger_favicon_url="/static/favicon-32x32.png",  # Optional
        custom_js_url="/static/custom_script.js",
    )


@app.get('/')
def main(token: str = Depends(oidc_google)):
    return "You are Authenticated"


自定义_swagger.py

import json
from typing import Any, Dict, Optional
from fastapi.encoders import jsonable_encoder
from fastapi.openapi.docs import swagger_ui_default_parameters
from starlette.responses import HTMLResponse

def get_swagger_ui_html(
    *,
    openapi_url: str,
    title: str,
    swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js",
    swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css",
    swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
    oauth2_redirect_url: Optional[str] = None,
    init_oauth: Optional[Dict[str, Any]] = None,
    swagger_ui_parameters: Optional[Dict[str, Any]] = None,
    custom_js_url: Optional[str] = None,
) -> HTMLResponse:
    current_swagger_ui_parameters = swagger_ui_default_parameters.copy()
    if swagger_ui_parameters:
        current_swagger_ui_parameters.update(swagger_ui_parameters)

    html = f"""
    <!DOCTYPE html>
    <html>
    <head>
    <link type="text/css" rel="stylesheet" href="{swagger_css_url}">
    <link rel="shortcut icon" href="{swagger_favicon_url}">
    <title>{title}</title>
    </head>
    <body>
    <div id="swagger-ui">
    </div>
    """
    
    if custom_js_url:
        html += f"""
        <script src="{custom_js_url}"></script>
        """

    html += f"""
    <script src="{swagger_js_url}"></script>
    <!-- `SwaggerUIBundle` is now available on the page -->
    <script>
    const ui = SwaggerUIBundle({{
        url: '{openapi_url}',
    """

    for key, value in current_swagger_ui_parameters.items():
        html += f"{json.dumps(key)}: {json.dumps(jsonable_encoder(value))},\n"

    if oauth2_redirect_url:
        html += f"oauth2RedirectUrl: window.location.origin + '{oauth2_redirect_url}',"

    html += """
    presets: [
        SwaggerUIBundle.presets.apis,
        SwaggerUIBundle.SwaggerUIStandalonePreset
        ],
    })"""

    if init_oauth:
        html += f"""
        ui.initOAuth({json.dumps(jsonable_encoder(init_oauth))})
        """

    html += """
    </script>
    </body>
    </html>
    """
    return HTMLResponse(html)


static/自定义脚本.js

function waitForElm(selector) {
    return new Promise(resolve => {
        if (document.querySelector(selector)) {
            return resolve(document.querySelector(selector));
        }

        const observer = new MutationObserver(mutations => {
            if (document.querySelector(selector)) {
                resolve(document.querySelector(selector));
                observer.disconnect();
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    });
}

waitForElm('.auth-wrapper').then((elm) => {
    var authWrapper = document.getElementsByClassName("auth-wrapper")[0];
    var btn = document.createElement("BUTTON");
    btn.innerHTML = "Click me";
    btn.id = "btn-id";
    btn.onclick = function() {
        alert("button is clicked");
    };
    authWrapper.append(btn);
});


不是通过 JavaScript 以编程方式创建按钮,您可以加载外部 HTML 文件(使用 JavaScript),其中包含按钮的 HTML 代码以及您可能想要插入的任何其他元素。下面的例子:

static/自定义脚本.js

function waitForElm(selector) {
   // same as in the previous code snippet
}

waitForElm('.auth-wrapper').then((elm) => {
   var authWrapper = document.getElementsByClassName("auth-wrapper")[0];
   fetch('/static/button.html')
      .then(response => response.text())
      .then(text => {
         const newDiv = document.createElement("div");
         newDiv.innerHTML = text;
         authWrapper.append(newDiv);
      });
});

static/按钮.html

<button onclick="alert('button is clicked');" class="btn authorize unlocked Google">
   <span>Authorize Google</span>
   <svg width="20" height="20">
      <use href="#unlocked" xlink:href="#unlocked"></use>
   </svg>
</button>

添加动态自定义内容

如果您想添加一些动态内容,而不是静态 JS/HTML 文件内容,您可以将内容直接作为字符串传递给get_swagger_ui_html()函数,或者使用静态内容与动态变量的组合,可以使用 Jinja2 模板添加动态变量。下面给出了示例,演示了对前面提供的代码进行的更改 - 其余代码应与上面相同。下面的例子中的动态变量是msg.

Example

app.py

# ...
from jinja2 import Environment, FileSystemLoader

def get_template():
    env = Environment(loader=FileSystemLoader('./static'))
    template = env.get_template('custom_script.js')
    context = {'msg': 'button is clicked!'}
    html = template.render(context)
    return html

@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
    return get_swagger_ui_html(
        openapi_url=app.openapi_url,
        title="My API",
        oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
        custom_js_content=get_template()
    )

自定义_swagger.py

def get_swagger_ui_html(
    *,
    # ...
    custom_js_content: Optional[str] = None,
) -> HTMLResponse:
    # ...
    
    if custom_js_content:
        html += f"""
        <script>{custom_js_content}</script>
        """
    # ...

static/自定义脚本.js

function waitForElm(selector) {
   // ...
}

waitForElm('.auth-wrapper').then((elm) => {
    var authWrapper = document.getElementsByClassName("auth-wrapper")[0];
    var btn = document.createElement("BUTTON");
    btn.innerHTML = `
       <span>Authorize Google</span>
       <svg width="20" height="20">
          <use href="#unlocked" xlink:href="#unlocked"></use>
       </svg>
   `;
    btn.className = "btn authorize unlocked Google";
    btn.onclick = function() {
        alert("{{msg}}");
    };
    authWrapper.append(btn);
});

or

static/自定义脚本.js

function waitForElm(selector) {
   // ...
}

waitForElm('.auth-wrapper').then((elm) => {
    var authWrapper = document.getElementsByClassName("auth-wrapper")[0];
    var html = `
    <button onclick="alert('{{msg}}');" class="btn authorize unlocked Google">
       <span>Authorize Google</span>
       <svg width="20" height="20">
          <use href="#unlocked" xlink:href="#unlocked"></use>
       </svg>
    </button>
    `;
    var newDiv = document.createElement("div");
    newDiv.innerHTML = html;
    authWrapper.append(newDiv);
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将自定义 HTML 内容添加到 FastAPI Swagger UI 文档? 的相关文章

随机推荐

  • 引用另一个别名的别名

    我需要识别一个引用 Cmder 中另一个别名命令的别名命令 例如 假设我定义了firstAlias 如下所示 alias firstAlias cd blah blah 比我创建另一个使用上面别名的别名 例如 alias secondAli
  • SQL SELECT 每月的第一天和最后一天。

    最亲爱的专业人士 我构建了一个查询来获取当月的第一天和最后一天 但该月第一天的时间戳有问题 declare FirstDOM datetime LastDOM datetime set FirstDOM select dateadd dd
  • Sqlite 获取最大 id 不起作用(?)

    我用这个 SELECT WHERE id MAX id FROM history 但我的查询是空的 我也尝试过这个 这个有效 SELECT MAX id AS max id FROM history 但显然我的查询只包含 max id 键
  • 在java中将美元(大十进制)转换为美分(整数)的最佳方法是什么?

    我必须将我的网络应用程序与支付网关集成 我想输入美元总金额 然后将其转换为美分 因为我的支付网关库接受美分金额 类型Integer 我找到Big Decimal在java中是操纵货币的最佳方式 目前我输入的金额为 50 美元 并将其转换为I
  • SQL Server 和 Java 之间的时间戳差异

    我需要将一个简单的过程从 Java 代码复制到 SQL Server 存储过程 它将进入生产中的 SQL Azure 数据库 但我正在针对本地 SQL Express 12 安装对其进行测试 该存储过程的一部分是将一些值连接成一个字符串 这
  • SSIS 和 MySQL - 表名分隔符问题

    我正在尝试使用 SQL Server 2008 SSIS 将行从 Access 数据库插入 MySQL 数据库 TITLE Microsoft SQL Server Management Studio ERROR 42000 MySQL O
  • 删除重复的文件扩展名

    我有数千个名为 filename gz gz gz gz gz gz gz gz gz gz gz 的文件 我正在使用这样的 find 命令find name gz 找到这些文件并使用 exec或者通过管道连接到 xargs 并使用一些神奇
  • 无法访问 sencha 中整个控制器的全局变量

    我一直在尝试访问一个控制器内的全局值 但无法访问它 我一直在关注这个如何在sencha中定义全局变量 https stackoverflow com questions 18095037 how to define global varia
  • C3.js将折线图Y轴的标签位置更改为Y轴居中

    我需要更改 Y 轴标签在 Y 轴上的位置 当前的六个位置选项无法满足我的场景 我也尝试使用 d3 进行自定义 但仍然没有成功 我创建了一个plnkr http plnkr co edit WzXVForyGJP01WJlAXj5 p pre
  • 由于随机效应,lme 发出警告消息

    我有一个包含 5 个变量的数据框 批次 晶圆 序列号 电压 放大倍数 在此数据框中 有 1020 个按 Serial number 分组的子集 每个子集都有一定数量的测量数据点 电压放大 我将数据与 summary fit2 lme lt
  • 是否可以创建 DbContext 接口或抽象类并使用它来注入不同的 DbContext 对象?

    我有一个软件产品 数据库是在 SQLServer 上创建的 表和列名称是由开发团队定义的 然后使用数据库优先方法将模型导入到 Visual Studio 现在我们正在为其他公司开发相同类型的解决方案使用 ORACLE 并请求表和列的命名约定
  • MongoDB:对数据库的读/写是否并发?

    当百万个线程尝试执行时会发生什么read from and write to MongoDB同时 锁定是否发生在db level table level or row level 它发生在数据库级别 但是在 Mongo 2 0 中 有一些并
  • matplotlib 等高线图:对数刻度中的比例颜色条级别

    是否可以将颜色条的级别设置为对数比例 如下图所示 这是一些可以实现的示例代码 import matplotlib pyplot as plt import numpy as np from matplotlib colors import
  • 解决WinForms中的跨线程异常

    目前我正在使用 WinForms C 语言 并且必须在后台运行该应用程序 为此 我使用异步 当我运行该应用程序时 它显示一个异常 例如 跨线程操作无效 从创建它的线程以外的线程访问控制 我该如何解决这个错误 当对控件进行方法调用时 如果调用
  • 哪里可以获取其他 iOS 版本的 iOS 系统符号

    请注意 我要求提供一个可以下载这些符号的地方 或者要求一个明确的答案 此类网站被 Apple 禁止 重复 问题与我在问题中链接的问题类似 唯一建议的答案是访问物理设备或找到另一位拥有物理设备的开发人员 我已经符号化了故障转储 但只有我的应用
  • PHP 字符串转数组

    我有一个字符串 当我 var dump 返回以下内容时 string 20 key1 key1 value key2 key2 value 如何将其转换为一个数组 在 var dump 时返回以下内容 array 2 key1 gt str
  • MVC 5 阻止通过 Iframe 访问内容

    自从从 MVC4 升级到 MVC5 以来 我注意到我的网页中添加了一个额外的服务器标头 X 框架选项 SAMEORIGIN 我了解添加此标签的安全优势 但其中一个页面应该包含在其他项目 在其他域上 的 iframe 中 这个额外的标头会阻止
  • 将 git hook 添加到谷歌云存储库

    谷歌云附带的功能之一是git 仓库 https cloud google com source repositories docs 是否可以向此存储库添加挂钩 我想要收到推送 但我不知道如何访问 git hooks 如果您将代码托管在git
  • 假互联网差

    我正在尝试在网络状况不佳的情况下测试我的 iPhone 和 Android 应用程序 我记得不久前我读到过一个程序 它可以伪造不同类型的不良互联网 有谁记得这个程序叫什么或者是否有类似的东西我可以用来完成这个任务 对于 iOS 正如其他人所
  • 如何将自定义 HTML 内容添加到 FastAPI Swagger UI 文档?

    我需要在 FastAPI 应用程序的 Swagger UI 中添加一个自定义按钮 我发现这个答案 https stackoverflow com questions 74661044 add a custom javascript to t