Django Ninja 多个 API 文档

问题描述 投票:0回答:1

Django Ninja 允许自动生成 OpenApi 端点文档。但是,该文档仅适用于单个 API 对象,这意味着为了查看另一个 API 的文档,我需要更改 URL。

我的项目使用多个API版本。我想将文档托管在单个统一的 URL 下,而不必记住使用的 api 版本特定功能。

Django Ninja 的文档允许 API 版本控制,如此处所述。然而,这会导致上述问题。

有什么方法可以包含 API 版本切换器,就像我使用独立的 OpenAPI 文档一样?显然,我可以自己获取并托管原始文档,但我希望我缺少一个简单的配置和忘记解决方案,因为 Django Ninja 已经托管了它。

我尝试使用 Router 对象而不是 API 对象来组合不同的 api 版本。然而,这只是一种解决方法,并且会阻止某些功能正常工作。最重要的是,UI 中显示错误的 API 版本

django openapi django-ninja
1个回答
0
投票

这是一个有趣的问题。我从来没有冲动去做那样的事情(从来没有必要)。但由于你的问题,我决定查看

django-ninja
来源,了解那里的一切是如何组织的。所以是的,这是可能的,我想出了一个非常简单的解决方案。如果需要,您可以自行调整我的解决方案。

让我们继续看代码。对于我们的测试,我们只需要两个文件:

urls.py
和一些用于渲染 swagger 的模板,例如
templates/swagger.html
(我在项目根目录中有
templates
文件夹)。

# urls.py

from ninja import NinjaAPI
from ninja.openapi.docs import Swagger

from django.http import HttpRequest, HttpResponse
from django.urls import path


class CustomNinjaAPI(NinjaAPI):
    apps_register = []

    def __init__(self, **kwargs) -> None:
        super().__init__(**kwargs)
        type(self).apps_register.append(self)


class CustomSwagger(Swagger):
    template_cdn = 'templates/swagger.html'
    default_settings = {
        'layout': 'StandaloneLayout',
        'deepLinking': True,
    }

    def render_page(
            self,
            request: HttpRequest,
            api: CustomNinjaAPI,
            **kwargs) -> HttpResponse:

        if 'urls' not in self.settings:
            self.settings['urls'] = [
                {
                    'url': obj.docs.get_openapi_url(obj, kwargs),
                    'name': obj.version,
                }
                for obj in api.apps_register
            ]
        return super().render_page(request=request, api=api, **kwargs)


app_v1 = CustomNinjaAPI(docs=CustomSwagger(), version='v1')
app_v2 = CustomNinjaAPI(docs=CustomSwagger(), version='v2')


@app_v1.get(path='/hello/')
def say_hello(request):
    return {'result': 'HELLO!'}


@app_v2.get(path='/hi/')
def say_hi(request):
    return {'result': 'HI!'}


urlpatterns = [
    path('api/v1/', app_v1.urls),
    path('api/v2/', app_v2.urls),
]

如您所见 - 所有内容都在一个文件中。为了完成所有这些工作,我们需要创建自己的

ninja
类的子类:
Swagger
NinjaAPI
。我的类 -
CustomNinjaAPI
在类属性中注册所有实例,这是最终生成所有
urls
所必需的,以便传递给模板。这就是
CustomSwagger
的作用,它只是遍历
CustomNinjaAPI
类的所有实例,并为每个文档生成
url
(假设这些
urls
尚未在
settings
中指定)。设置字典被传递到
HTML
模板。

这就是“HTML”模板的样子:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
  <meta charset="UTF-8">
  <title>ServiceDesk Service Swagger</title>
  <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.18.2/swagger-ui.css">
</head>
<body>

<div id="swagger-ui"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.18.2/swagger-ui-standalone-preset.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.18.2/swagger-ui-bundle.js"></script>
<script type="application/json" id="swagger-settings">{{ swagger_settings | safe }}</script>
<script>
    window.onload = () => {
        const baseConfig = {
          dom_id: '#swagger-ui',
          presets: [
            SwaggerUIBundle.presets.apis,
            SwaggerUIStandalonePreset,
          ],
          plugins: [
            SwaggerUIBundle.plugins.DownloadUrl,
          ],
        };

        const configJson = document
          .querySelector("#swagger-settings")
          .textContent;

        const configObject = Object.assign(
          {},
          JSON.parse(configJson),
          baseConfig
        );

        window.ui = SwaggerUIBundle(configObject);
    };
</script>
</body>
</html>

模板尽可能简单。您还可以在ninja的源代码中检查它是如何完成的,并根据需要扩展它。

唯一的细微差别是,要使此功能适合您,您需要从

django-ninja
中删除
settings.INSTALLED_APPS
(一切都会像以前那样工作),因为将它放在那里,
ninja
,将使用不同的模板 !我没有“为每个人”做这件事的目标,只是一个如何实现它的例子。

结果本身现在可以通过任何文档链接获得:

/api/v2/docs
/api/v1/docs
。这就是它的样子: v1_docs

v2_docs

© www.soinside.com 2019 - 2024. All rights reserved.