需求描述
使用python的flask框架开发api时,发现了一个插件flask_docs,可以通过注释自动生成api文档,类似ava的swagger
flask-docs使用介绍,点击看作者kwkwc大佬原文
但是目前该插件不支持自定义树节点的大小标题,生成的文档难以让外人理解。 于是重写了里面方法,实现了树节点大小标题的自定义。
效果
优化逻辑
- 父节点显示的是蓝图的路径,可以通给蓝图命别名的方式,重写显示父节点的代码,显示蓝图对应的别名。
- 子节点是 <· method(注释)> 的形式,可以将他们换个位置,变成 < · 注释(method) > 的显示方式。
代码实现
逻辑实现
from flask_docs import ApiDoc
app.config.setdefault("API_DOC_MEMBER_RENAME", [])
···
for item in ["2. 外观全景", "3. 楼宇设施", "4. 综合安防", "5. 信息设施", '1. 通用接口']
app.config["API_DOC_MEMBER_RENAME"].append(item)
ApiDoc._get_api_data = get_api_data
重写的方法(长#符号中间的是重写的类容)。
def get_api_data(self):
"""
重构flask_docs里面的对应方法,支持重命名树节点
"""
from flask_docs import logger as apidocs_log, PROJECT_NAME
data_dict = {}
for rule in current_app.url_map.iter_rules():
f = str(rule).split("/")[1]
if f not in current_app.config["API_DOC_MEMBER"]:
continue
index = current_app.config["API_DOC_MEMBER"].index(f)
f_capitalize = app.config["API_DOC_MEMBER_RENAME"][index]
if f_capitalize not in data_dict:
data_dict[f_capitalize] = {"children": []}
api = {
"name": "",
"name_extra": "",
"url": "",
"method": "",
"doc": "",
"doc_md": "",
"router": f_capitalize,
"api_type": "api",
}
try:
func = current_app.view_functions[rule.endpoint]
name = self._get_api_name(func)
url = str(rule)
method = " ".join([r for r in rule.methods if r in current_app.config["API_DOC_METHODS_LIST"]])
if method:
url = "{}\t[{}]".format(url, "\t".join(method.split(" ")))
result = filter(
lambda x: x["name"] == name,
data_dict[f_capitalize]["children"],
)
result_list = list(result)
if len(result_list) > 0:
result_list[0]["url"] = result_list[0]["url"] + " " + url
result_list[0]["url"] = " ".join(list(set(result_list[0]["url"].split(" "))))
result_list[0]["method"] = result_list[0]["method"] + \
" " + method
result_list[0]["method"] = " ".join(list(set(result_list[0]["method"].split(" "))))
raise RuntimeError
api["url"] = url
api["method"] = method
doc = self._get_api_doc(func)
(
api["doc"],
api["name_extra"],
api["doc_md"],
) = self._get_doc_name_extra_doc_md(doc)
if api["name_extra"] == '':
api["name"] = name
else:
api["name"] = api["name_extra"]
api["name_extra"] = name
""" 这里是我的项目里面做的通过在线文档自动测试,以及自动填充在线文档。
if YAMLCONFIG is not None and api["doc_md"].index('__resp_example__') >= 0:
start = api["doc_md"].index(YAMLCONFIG.apidoc.publichost)
end = api["doc_md"].index('```', start)
url = api["doc_md"][start:end].replace(YAMLCONFIG.apidoc.publichost, YAMLCONFIG.apidoc.localhost)
resp = requests.request(method, url)
api["doc_md"] = api["doc_md"].replace('__resp_example__', resp.text)
"""
except Exception as e:
apidocs_log.exception("{} error - {}".format(PROJECT_NAME, e))
else:
data_dict[f_capitalize]["children"].append(api)
if data_dict[f_capitalize]["children"] == []:
data_dict.pop(f_capitalize)
else:
data_dict[f_capitalize]["children"].sort(key=lambda x: x["name"])
return data_dict
我的项目中的逻辑实现,将蓝图和文档的配置内置了,外面的调用变得简单:
def RegisterBlueprintAndDoc(bluePrintList, doc_title=None, doc_version=None):
"""
flask配置文档成员,并注册蓝图
@bluePrintList:可以将蓝图对象放到list/tuple里面进行注册。也支持通过dict类型重命名Flask_Docs文档里面的树节点:{BluePrint_Object:"rename"}
@doc_title: 在线文档的标题,如果使用yaml配置,会优先读取YAMLCONFIG.apidoc.title
@doc_version: 在线文档的版本,如果使用yaml配置,会优先读取YAMLCONFIG.apidoc.version
"""
nameList = []
if type(bluePrintList) in (list, tuple):
···
elif type(bluePrintList) == dict:
app.config.setdefault("API_DOC_MEMBER_RENAME", [])
for key, value in bluePrintList.items():
CORS(key)
app.register_blueprint(key, url_prefix="/{}".format(key.name))
nameList.append(key.name)
app.config["API_DOC_MEMBER_RENAME"].append(value)
app.config["API_DOC_MEMBER"] = nameList
ApiDoc._get_api_data = get_api_data
else:
logger.error('registerBlueprint调用失败,参数类型不支持')
ApiDoc(app, doc_title, doc_version)
API.RegisterBlueprintAndDoc({Panaroma: "2. 外观全景", BuildDevice: "3. 楼宇设施", Security: "4. 综合安防", InfoDevice: "5. 信息设施", Comm: '1. 通用接口'})
|