Python 实现 Swagger yaml 格式 api 文档合并
来源:互联网 发布:知乎用户数量一亿 编辑:程序博客网 时间:2024/06/07 05:58
需求来源
公司业务系统中,API文档定义使用了Swagger,由于多人开发中每个人开发的节点不同,整体的业务过于复杂,维护一套完整的 API 文档十分繁重,且容易出现误修改,所以用 python 实现了多个 yaml 文件 OpenAPI 文档合并工具。
Open API 相关资料
推荐阅读
Writing OpenAPI (Swagger) Specification Tutorial
https://apihandyman.io/writing-openapi-swagger-specification-tutorial-part-1-introduction/Swagger 从入门到精通 (第一个链接的译文)
https://www.gitbook.com/book/huangwenchao/swagger/detailsOpenAPI Specification 2.0 (手册,无需通读)
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md
推荐工具
- Prism (OpenAPI Mock 工具)
http://stoplight.io/platform/prism/
YAML示例
swagger: "2.0"info: version: "0.0.1" title: XXX description: XXXhost: localhost:4010schemes: - httpbasePath: /api/v1produces: - application/jsonpaths: ... # 路由项definitions: ... # 定义项responses: ... # 响应消息中定义项parameters: ... # 路径参数定义项
核心逻辑
1. 各个模块(paths,definitions等)的查找分离
def findstring(all_the_text): head_string = re.search(r".*paths:", all_the_text, re.S).group() # 删除 paths: 之上的头部信息 all_the_text = all_the_text.replace(head_string, '\npaths:') # 获取模块名,以此为匹配条件 module_name_strings = re.findall(r"(\n\w*:)", all_the_text, re.S) # print(module_name_strings) # 新建字典存放模块内容 modules = {} for i in range(len(module_name_strings)): if i + 1 <len(module_name_strings): modules[(module_name_strings[i].replace("\n","").replace(":",""))] = \ re.search(module_name_strings[i]+".*"+module_name_strings[i+1], all_the_text, re.S).group()\ .replace(module_name_strings[i],"").replace(module_name_strings[i+1],"") else: modules[(module_name_strings[i].replace("\n","").replace(":",""))] = \ re.search(module_name_strings[i]+".*", all_the_text, re.S).group().replace(module_name_strings[i],"") # 应用平移函数 for key in modules: modules[key] = remove(modules[key]) # remove 在 2.中实现 return modules
2. 代码整体平移,解决行首空格数量不一致问题
# 平移代码def remove(text): if text != '': # 去除代码中的注释 text = re.sub(r'\n(\s*)#(.*)', "", text) spaces = re.search(r"\n\s*", text, re.S).group() spaces_len = len(spaces) - 1 # 计算首行 空格数 if spaces_len != 2: text = text.replace('\n'+' '*spaces_len ,'\n ') return text
3. 检测 API 各部分重复定义的情况,并提供自动合并(保留最后一个)
# 去除重定义def remove_duplicate(name,text): #name是模块名称 names = re.findall(r"(\n\s\s\w+:)", text, re.S) names_set = set(names) remove_module = {} duplicate = False for item in names_set: if names.count(item) > 1: print("发现重定义的%s: %s 次数:%s" %(name,item.replace("\n ","").replace(":",""),names.count(item))) remove_module[item] = names.count(item) duplicate = True # 发现重复,进入去重逻辑 if duplicate: print('是否自动合并?(Y/N)') flag = input() if (flag == 'Y') or (flag == 'y'): print('自动合并中...') for i in range(len(names)): if (names[i] in remove_module.keys() and remove_module[names[i]] > 1): remove_string = re.search(names[i]+"(.*?)"+names[i+1], text, re.S).group() if names[i+1] != names[i]: remove_string = remove_string.replace(names[i+1],"") else: remove_string = names[i] + remove_string.replace(names[i+1],"") text = text.replace(remove_string,"",1) remove_module[names[i]] = remove_module[names[i]] - 1 else: print('已忽略,请手工处理...') return text
整体代码
import reimport os# 平移代码def remove(text): if text != '': # 去除代码中的注释 text = re.sub(r'\n(\s*)#(.*)', "", text) spaces = re.search(r"\n\s*", text, re.S).group() spaces_len = len(spaces) - 1 # 计算首行 空格数 if spaces_len != 2: text = text.replace('\n'+' '*spaces_len ,'\n ') return text# 查找指定代码段def findstring(all_the_text): head_string = re.search(r".*paths:", all_the_text, re.S).group() # 删除 paths: 之上的头部信息 all_the_text = all_the_text.replace(head_string, '\npaths:') # print(all_the_text) # 获取模块名,以此为匹配条件 module_name_strings = re.findall(r"(\n\w*:)", all_the_text, re.S) # print(module_name_strings) # 新建字典存放模块内容 modules = {} for i in range(len(module_name_strings)): if i + 1 <len(module_name_strings): modules[(module_name_strings[i].replace("\n","").replace(":",""))] = \ re.search(module_name_strings[i]+".*"+module_name_strings[i+1], all_the_text, re.S).group()\ .replace(module_name_strings[i],"").replace(module_name_strings[i+1],"") else: modules[(module_name_strings[i].replace("\n","").replace(":",""))] = \ re.search(module_name_strings[i]+".*", all_the_text, re.S).group().replace(module_name_strings[i],"") # 应用平移函数 for key in modules: modules[key] = remove(modules[key]) return modules# 去除重定义函数def remove_duplicate(name,text): names = re.findall(r"(\n\s\s\w+:)", text, re.S) names_set = set(names) remove_module = {} duplicate = False for item in names_set: if names.count(item) > 1: print("发现重定义的%s: %s 次数:%s" %(name,item.replace("\n ","").replace(":",""),names.count(item))) remove_module[item] = names.count(item) duplicate = True # 发现重复,进入去重 if duplicate: print('是否自动合并?(Y/N)') flag = input() if (flag == 'Y') or (flag == 'y'): print('自动合并中...') for i in range(len(names)): if (names[i] in remove_module.keys() and remove_module[names[i]] > 1): remove_string = re.search(names[i]+"(.*?)"+names[i+1], text, re.S).group() if names[i+1] != names[i]: remove_string = remove_string.replace(names[i+1],"") else: remove_string = names[i] + remove_string.replace(names[i+1],"") text = text.replace(remove_string,"",1) remove_module[names[i]] = remove_module[names[i]] - 1 else: print('已忽略,请手工处理...') return text# 获取文件列表def GetFileList(dir, fileList): newDir = dir if os.path.isfile(dir): fileList.append(dir) elif os.path.isdir(dir): for s in os.listdir(dir): #如果需要忽略某些文件夹,使用以下代码 if not (".yaml" in s) or ("api-all" in s) or ("api-combine" in s): continue newDir=os.path.join(dir,s) GetFileList(newDir, fileList) return fileList# Main 代码string_all = {}string_all['paths'] = ''string_all['definitions'] = ''string_all['responses'] = ''string_all['parameters'] = ''file_names = GetFileList(os.getcwd(), [])print("检测到当前目录以下yaml文件:")for e in file_names: print(e)print('共 %s 个文件需合并'%(len(file_names)))print('\n正在合并中...\n')# 循环读取文件for file_name in file_names: file_object = open(file_name,'r',encoding= 'utf8') try: all_the_text = file_object.read() finally: file_object.close() text_modules = findstring(all_the_text) if 'paths' in text_modules: string_all['paths'] += text_modules['paths'] if 'definitions' in text_modules: string_all['definitions'] += text_modules['definitions'] if 'responses' in text_modules: string_all['responses'] += text_modules['responses'] if 'parameters' in text_modules: string_all['parameters'] += text_modules['parameters']# 去重for key in string_all: string_all[key] = remove_duplicate(key,string_all[key])module = '''swagger: '2.0'info: title: XXX description: XXX version: "1.0.0"host: localhost:4010schemes: - httpbasePath: /api/v1produces: - application/jsonpaths:%sdefinitions:%sresponses:%sparameters:%s''' % (string_all['paths'], string_all['definitions'], string_all['responses'], string_all['parameters'])# parameters 不存在时,去掉 parameters:if string_all['parameters'] == '': module = module.replace('\nparameters:','')# 去除多余空行module = re.sub(r"\n\s*\n", "\n", module)result_file = open('api-combine.yaml','w+',encoding= 'utf8')result_file.write(module)print('api-combine.yaml生成成功!!!');input()
使用方式
将代码放到单独的 .py 文件中,置于 yaml API 文档文件夹目录下执行即可,需安装Python3.x。
小尾巴
笔者的python并不精通,O(∩_∩)O~ ,代码仍需改进,可能存在各种bug,仅供参考!
0 0
- Python 实现 Swagger yaml 格式 api 文档合并
- Swagger编写API文档的YAML中文示例
- Swagger生成API文档
- 解决 Python ruamel.yaml 读写 yaml 文档 format 格式不一致问题
- 使用 ruamel.yaml 读写 yaml 文档 Python 操作笔记
- 使用Swagger,Swagger-UI生成REST API接口文档
- 使用 swagger 自动生成 API 文档
- 如何使用 Grape-Swagger 生成 API 文档
- jersey+swagger,构建api文档平台
- springmvc集成Swagger自动生成api文档
- swagger 生成 PHP restful API 接口文档
- Java Restfull API 文档生成 Swagger UI
- swagger 生成 PHP restful API 接口文档
- Swagger UI教程 API 文档神器
- springboot利用swagger构建api文档
- API文档工具-Swagger的集成
- SpringBoot项目API文档工具-Springfox Swagger
- swagger和gitlab结合做API文档
- Canny边缘检测算法的实现
- linux 进度条
- 一个网站完整详细的SEO优化方案
- 论程序员的装逼手册
- linux例子
- Python 实现 Swagger yaml 格式 api 文档合并
- java.lang.NoSuchMethodError: antlr.collections.AST.getLine()I 解决方法
- javaWeb安全问题
- CSS:readonly与disabled属性
- synchronized关键字
- 【数值计算】数值解析--二阶偏微分方程的3种基本形
- 数据结构-递归实现二叉树
- Cassandra 学习笔记
- Cubietruck Plus linux-sdk环境搭建以及系统固件编译步骤