Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions docs/Tutorial/UI_Templates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
Flask OpenAPI3 supports [Swagger](https://github.com/swagger-api/swagger-ui), [Redoc](https://github.com/Redocly/redoc)
and [RapiDoc](https://github.com/rapi-doc/RapiDoc) templates by default.

You can customize templates use `ui_templates` in initializing OpenAPI.

```python
ui_templates = {
"swagger": swagger_html_string,
"rapipdf": rapipdf_html_string
}

app = OpenAPI(__name__, info=info, ui_templates=ui_templates)
```

In the above example, `swagger` will overwrite the original template and `rapipdf` is a new template.

You can do anything with `swagger_html_string`, `rapipdf_html_string` or `any_html_string`.

**swagger_html_string:**

```html hl_lines="5 32"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Custom Title</title>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist/swagger-ui.css">
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}

*, *:before, *:after {
box-sizing: inherit;
}

body {
margin: 0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function () {
// Begin Swagger UI call region
window.ui = SwaggerUIBundle({
url: "{{api_doc_url}}",
dom_id: "#swagger-ui",
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
}
</script>
</body>
</html>
```

**rapipdf_html_string:**

```html hl_lines="9"
<!doctype html>
<html>
<head>
<script src="https://unpkg.com/rapipdf/dist/rapipdf-min.js"></script>
</head>
<body>
<rapi-pdf
style="width:700px; height:40px; font-size:18px;"
spec-url="{{api_doc_url}}"
button-bg="#b44646"
></rapi-pdf>
</body>
</html>
```

!!! info

`api_doc_url` is a necessary parameter for rendering template, so you must define it in your template.
105 changes: 105 additions & 0 deletions examples/custom_ui_templates_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
# @Author : llc
# @Time : 2023/2/3 15:14
from pydantic import BaseModel

from flask_openapi3 import Info, Tag
from flask_openapi3 import OpenAPI

info = Info(title="book API", version="1.0.0")
swagger_html_string = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Custom Title</title>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist/swagger-ui.css">
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}

*, *:before, *:after {
box-sizing: inherit;
}

body {
margin: 0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function () {
// Begin Swagger UI call region
window.ui = SwaggerUIBundle({
url: "{{api_doc_url}}",
dom_id: "#swagger-ui",
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
}
</script>
</body>
</html>
"""

rapipdf_html_string = """
<!doctype html>
<html>
<head>
<script src="https://unpkg.com/rapipdf/dist/rapipdf-min.js"></script>
</head>
<body>
<rapi-pdf
style = "width:700px; height:40px; font-size:18px;"
spec-url = "{{api_doc_url}}"
button-bg = "#b44646"
> </rapi-pdf>
</body>
</html>
"""
ui_templates = {
"swagger": swagger_html_string,
"rapipdf": rapipdf_html_string
}
app = OpenAPI(__name__, info=info, ui_templates=ui_templates)

book_tag = Tag(name='book', description='Some Book')


class BookQuery(BaseModel):
age: int
author: str


@app.get('/book', tags=[book_tag])
def get_book(query: BookQuery):
"""get books
get all books
"""
return {
"code": 0,
"message": "ok",
"data": [
{"bid": 1, "age": query.age, "author": query.author},
{"bid": 2, "age": query.age, "author": query.author}
]
}


if __name__ == '__main__':
app.run(debug=True)
71 changes: 45 additions & 26 deletions flask_openapi3/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from copy import deepcopy
from typing import Optional, List, Dict, Union, Any, Type, Callable, Tuple

from flask import Flask, Blueprint, render_template
from flask import Flask, Blueprint, render_template, render_template_string
from pydantic import BaseModel

from .blueprint import APIBlueprint
Expand Down Expand Up @@ -39,6 +39,7 @@ def __init__(
swagger_url: str = "/swagger",
redoc_url: str = "/redoc",
rapidoc_url: str = "/rapidoc",
ui_templates: Optional[Dict[str, str]] = None,
servers: Optional[List[Server]] = None,
external_docs: Optional[ExternalDocumentation] = None,
**kwargs: Any
Expand All @@ -64,6 +65,7 @@ def __init__(
swagger_url: The Swagger UI documentation. Defaults to `/swagger`.
redoc_url: The Redoc UI documentation. Defaults to `/redoc`.
rapidoc_url: The RapiDoc UI documentation. Defaults to `/rapidoc`.
ui_templates: Custom UI templates, which used to overwrite or add UI documents.
servers: An array of Server Objects, which provide connectivity information to a target server.
external_docs: Allows referencing an external resource for extended documentation.
See: https://spec.openapis.org/oas/v3.0.3#external-documentation-object
Expand Down Expand Up @@ -92,11 +94,14 @@ def __init__(
if not isinstance(oauth_config, OAuthConfig):
raise TypeError("`initOAuth` must be `OAuthConfig`")
self.oauth_config = oauth_config
if doc_ui:
self._init_doc()
self.doc_expansion = doc_expansion
if ui_templates is None:
ui_templates = dict()
self.ui_templates = ui_templates
self.severs = servers
self.external_docs = external_docs
if doc_ui:
self._init_doc()
# add openapi command
self.cli.add_command(openapi_command)

Expand All @@ -120,32 +125,46 @@ def _init_doc(self) -> None:
endpoint="api_doc",
view_func=lambda: self.api_doc
)
blueprint.add_url_rule(
rule=self.swagger_url,
endpoint="swagger",
view_func=lambda: render_template(
"swagger.html",
api_doc_url=self.api_doc_url.lstrip("/"),
doc_expansion=self.doc_expansion,
oauth_config=self.oauth_config.dict() if self.oauth_config else None
# iter ui_templates
for key, value in self.ui_templates.items():
blueprint.add_url_rule(
rule=f"/{key}",
endpoint=key,
# pass default value to source
view_func=lambda source=value: render_template_string(
source,
api_doc_url=self.api_doc_url.lstrip("/")
)
)
)
blueprint.add_url_rule(
rule=self.redoc_url,
endpoint="redoc",
view_func=lambda: render_template(
"redoc.html",
api_doc_url=self.api_doc_url.lstrip("/")
if self.swagger_url.strip("/") not in self.ui_templates.keys():
blueprint.add_url_rule(
rule=self.swagger_url,
endpoint="swagger",
view_func=lambda: render_template(
"swagger.html",
api_doc_url=self.api_doc_url.lstrip("/"),
doc_expansion=self.doc_expansion,
oauth_config=self.oauth_config.dict() if self.oauth_config else None
)
)
)
blueprint.add_url_rule(
rule=self.rapidoc_url,
endpoint="rapidoc",
view_func=lambda: render_template(
"rapidoc.html",
api_doc_url=self.api_doc_url.lstrip("/")
if self.redoc_url.strip("/") not in self.ui_templates.keys():
blueprint.add_url_rule(
rule=self.redoc_url,
endpoint="redoc",
view_func=lambda: render_template(
"redoc.html",
api_doc_url=self.api_doc_url.lstrip("/")
)
)
if self.rapidoc_url.strip("/") not in self.ui_templates.keys():
blueprint.add_url_rule(
rule=self.rapidoc_url,
endpoint="rapidoc",
view_func=lambda: render_template(
"rapidoc.html",
api_doc_url=self.api_doc_url.lstrip("/")
)
)
)
blueprint.add_url_rule(
rule="/",
endpoint="index",
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ plugins:
Operation: 路由操作
Request: 请求
Response: 响应
UI Templates: 自定义模板
Example: 示例
API Reference: API 参考
LICENSE: 许可
Expand All @@ -85,6 +86,7 @@ nav:
- Operation: Tutorial/Operation.md
- Request: Tutorial/Request.md
- Response: Tutorial/Response.md
- UI Templates: Tutorial/UI_Templates.md
- JSON: Tutorial/JSON.md
- Example: Example.md
- API Reference:
Expand Down
Loading