在Python的FastAPI Swagger UI文档网页中添加自定义JavaScript

4
我希望能够将自定义的JavaScript文件或代码加载到FastAPI Swagger UI网页中,以在创建FastAPI对象时添加一些动态交互。
例如,在Swagger UI的文档网页中,我想要:
<script src="custom_script.js"></script> 


<script> alert('worked!') </script>

我尝试了:

api = FastAPI(docs_url=None)

api.mount("/static", StaticFiles(directory="static"), name="static")

@api.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
    return get_swagger_ui_html(
        openapi_url=api.openapi_url,
        title=api.title + " - Swagger UI",
        oauth2_redirect_url=api.swagger_ui_oauth2_redirect_url,
        swagger_js_url="/static/sample.js",
        swagger_css_url="/static/sample.css",
    )

但它不起作用。有没有一种方法可以在Python的FastAPI Swagger UI文档网页中插入我的自定义JavaScript代码?

2个回答

3
如果你看一下从fastapi.openapi.docs导入的get_swagger_ui_html函数,你会发现文档页面的HTML是通过字符串插值/拼接手动构建的。很容易修改这个函数来包含一个额外的脚本元素,如下所示:
# custom_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)

新增了一个名为custom_js_url的新可选参数:
    custom_js_url: Optional[str] = None,

如果为该参数提供了一个值,那么一个脚本元素将被直接插入到 DOM 中,在 swagger_js_url 的脚本元素之前(这是任意选择,您可以根据需要更改自定义脚本元素的位置)。

    if custom_js_url:
        html += f"""
        <script src="{custom_js_url}"></script>
        """

如果没有提供值,则生成的HTML与原始函数相同。
请记得更新您的导入语句以获取get_swagger_ui_html,并按照下面所示更新/docs端点的函数。
from fastapi import FastAPI
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
import os

app = FastAPI(docs_url=None) 
path_to_static = os.path.join(os.path.dirname(__file__), 'static')
app.mount("/static", StaticFiles(directory=path_to_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="My API",
        oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
        swagger_js_url="/static/swagger-ui-bundle.js",
        swagger_css_url="/static/swagger-ui.css",
        # swagger_favicon_url="/static/favicon-32x32.png",
        custom_js_url="/static/custom_script.js",
    )

这仍然是一个相当粗糙的解决方案,但我认为它比在 swagger-ui-bundle.js 文件中放置大量自定义 JavaScript 更清晰和更易维护。

未来的读者可能也会发现这个答案有帮助。 - Chris

2

最终,我把它搞定了。这是我所做的:

from fastapi.openapi.docs import (
    get_redoc_html,
    get_swagger_ui_html,
    get_swagger_ui_oauth2_redirect_html,
)
from fastapi.staticfiles import StaticFiles

api = FastAPI(docs_url=None) 

path_to_static = os.path.join(os.path.dirname(__file__), 'static')
logger.info(f"path_to_static: {path_to_static}")
api.mount("/static", StaticFiles(directory=path_to_static), name="static")

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

重要提示:

  1. 请确保静态路径正确且所有文件都位于静态文件夹中,通常情况下静态文件夹应与创建FastAPI对象的脚本位于同一文件夹中。

例如:

 -parent_folder
     Build_FastAPI.py
     -static_folder
         custom_script.js
         custom_css.css
  1. 在互联网上找到swagger-ui-bundle.js,将其所有内容复制粘贴到custom_script.js中,然后在custom_script.js的开头或结尾添加您自定义的JavaScript代码。

例如:

setTimeout(function(){alert('My custom script is working!')}, 5000);
...
.....
/*! For license information please see swagger-ui-bundle.js.LICENSE.txt */
            !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUIBundle=t():e.SwaggerUIBundle=t()}
...
.....
  1. 保存并刷新您的浏览器,就完成了!

如果有更好的答案,请随时提供,最佳答案将被接受!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接