http-content-parser 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- http_content_parser-0.0.1/.gitignore +26 -0
- http_content_parser-0.0.1/LICENSE +19 -0
- http_content_parser-0.0.1/PKG-INFO +15 -0
- http_content_parser-0.0.1/README.md +3 -0
- http_content_parser-0.0.1/pyproject.toml +18 -0
- http_content_parser-0.0.1/requirements.txt +1 -0
- http_content_parser-0.0.1/src/http_content_parser/__init__.py +0 -0
- http_content_parser-0.0.1/src/http_content_parser/curl_parser.py +118 -0
- http_content_parser-0.0.1/src/http_content_parser/generate_api_file.py +122 -0
- http_content_parser-0.0.1/src/http_content_parser/openapi_parser.py +159 -0
- http_content_parser-0.0.1/src/http_content_parser/postman_parser.py +44 -0
- http_content_parser-0.0.1/src/http_content_parser/req_data.py +116 -0
- http_content_parser-0.0.1/src/http_content_parser/swagger2_parser.py +130 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# General
|
|
2
|
+
.DS_Store
|
|
3
|
+
.AppleDouble
|
|
4
|
+
.LSOverride
|
|
5
|
+
|
|
6
|
+
# Icon must end with two \r
|
|
7
|
+
Icon
|
|
8
|
+
|
|
9
|
+
# Thumbnails
|
|
10
|
+
._*
|
|
11
|
+
|
|
12
|
+
# Files that might appear in the root of a volume
|
|
13
|
+
.DocumentRevisions-V100
|
|
14
|
+
.fseventsd
|
|
15
|
+
.Spotlight-V100
|
|
16
|
+
.TemporaryItems
|
|
17
|
+
.Trashes
|
|
18
|
+
.VolumeIcon.icns
|
|
19
|
+
.com.apple.timemachine.donotpresent
|
|
20
|
+
|
|
21
|
+
# Directories potentially created on remote AFP share
|
|
22
|
+
.AppleDB
|
|
23
|
+
.AppleDesktop
|
|
24
|
+
Network Trash Folder
|
|
25
|
+
Temporary Items
|
|
26
|
+
.apdisk
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2018 The Python Packaging Authority
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: http_content_parser
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: parse http's payload and response
|
|
5
|
+
Author-email: max su <suleiabc@gmail.com>
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# HttpParser Package
|
|
14
|
+
|
|
15
|
+
This is a http content parser package.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "http_content_parser"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="max su", email="suleiabc@gmail.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "parse http's payload and response"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.8"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pyyaml
|
|
File without changes
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
|
2
|
+
class CurlParser(object):
|
|
3
|
+
def split_url(self, url: str, split_char: str):
|
|
4
|
+
# TODO 考虑url中没有http字符的情况(只出现在Postman导出的curl)
|
|
5
|
+
url_params = {}
|
|
6
|
+
if '?' in url:
|
|
7
|
+
ss = url.split('?')
|
|
8
|
+
url = ss[0]
|
|
9
|
+
url_params = ss[1]
|
|
10
|
+
url_params = self.form_str_to_dict(url_params)
|
|
11
|
+
urls = url.split('/')
|
|
12
|
+
url_path = ''
|
|
13
|
+
for i in range(3, len(urls)):
|
|
14
|
+
url_path += urls[i] + split_char
|
|
15
|
+
return {'url_path': url_path, 'url_params': url_params}
|
|
16
|
+
|
|
17
|
+
def form_str_to_dict(self, form_data):
|
|
18
|
+
"""将form表单参数转成dict类型"""
|
|
19
|
+
item_dict = {}
|
|
20
|
+
if '&' in form_data:
|
|
21
|
+
for item in form_data.split('&'):
|
|
22
|
+
line = item.split('=')
|
|
23
|
+
if len(line) == 2:
|
|
24
|
+
item_dict[line[0]] = line[1]
|
|
25
|
+
if len(line) == 1:
|
|
26
|
+
item_dict[line[0]] = ''
|
|
27
|
+
else:
|
|
28
|
+
if '=' in form_data:
|
|
29
|
+
line = form_data.split('=')
|
|
30
|
+
item_dict[line[0]] = line[1]
|
|
31
|
+
return item_dict
|
|
32
|
+
|
|
33
|
+
# 处理curl中data部分的数据,把多行转换成一行数据
|
|
34
|
+
def reduce_curl_data_part(self, lines, s, e):
|
|
35
|
+
new_lines = []
|
|
36
|
+
for i in range(s, e):
|
|
37
|
+
new_line = lines[i]
|
|
38
|
+
if '--data ' in lines[i]:
|
|
39
|
+
# 判断请求的body是否完整,根据''单引号是否是两个
|
|
40
|
+
char_count = lines[i].count('\'')
|
|
41
|
+
if char_count == 1:
|
|
42
|
+
i += 1
|
|
43
|
+
while i < e:
|
|
44
|
+
new_line += lines[i]
|
|
45
|
+
if lines[i].count('\'') == 1:
|
|
46
|
+
break
|
|
47
|
+
i += 1
|
|
48
|
+
new_lines.append(new_line)
|
|
49
|
+
return new_lines
|
|
50
|
+
|
|
51
|
+
def get_curl_line_num_scope(self, lines):
|
|
52
|
+
start_num = 0
|
|
53
|
+
num = 0
|
|
54
|
+
curl_num = 0
|
|
55
|
+
line_num_array = []
|
|
56
|
+
for line in lines:
|
|
57
|
+
# 拆分多个curl
|
|
58
|
+
if 'curl' in line:
|
|
59
|
+
curl_num += 1
|
|
60
|
+
if curl_num >= 2:
|
|
61
|
+
line_num_array.append([start_num, num-1])
|
|
62
|
+
curl_num = 1
|
|
63
|
+
start_num = num
|
|
64
|
+
num += 1
|
|
65
|
+
if num == len(lines):
|
|
66
|
+
line_num_array.append([start_num, num])
|
|
67
|
+
return line_num_array
|
|
68
|
+
|
|
69
|
+
def split_curl_to_struct(self, lines, s, e, curl_filter=None) -> dict:
|
|
70
|
+
req_data = {}
|
|
71
|
+
header = {}
|
|
72
|
+
reduced_lines = self.reduce_curl_data_part(lines=lines, s=s, e=e)
|
|
73
|
+
for i in range(0, len(reduced_lines)):
|
|
74
|
+
lines_i_str = str(reduced_lines[i])
|
|
75
|
+
line_i_list = lines_i_str.split(' ')
|
|
76
|
+
if 'curl' in lines_i_str:
|
|
77
|
+
if curl_filter:
|
|
78
|
+
if curl_filter not in lines_i_str:
|
|
79
|
+
# 如果curl_filter 不存在于当前Url中,则跳过本次循环
|
|
80
|
+
continue
|
|
81
|
+
for line_sub in line_i_list:
|
|
82
|
+
if line_sub.lower() in ['get', 'put', 'post', 'delete']:
|
|
83
|
+
req_data['method'] = line_sub.lower().replace('\'', '')
|
|
84
|
+
elif 'http' in line_sub:
|
|
85
|
+
req_data['original_url'] = line_sub.replace('\'', '')
|
|
86
|
+
# 兼容Postman中url没有http开头的情况
|
|
87
|
+
elif '/' in line_sub:
|
|
88
|
+
req_data['original_url'] = line_sub.replace('\'', '')
|
|
89
|
+
elif '-X ' in lines_i_str:
|
|
90
|
+
line_i_list = lines_i_str.split(' \'')
|
|
91
|
+
req_data['method'] = line_i_list[1].lower().replace(
|
|
92
|
+
'\'', '').replace(' ', '').replace('\\\n', '')
|
|
93
|
+
elif '-H \'' in lines_i_str or '--header' in lines_i_str:
|
|
94
|
+
line_i_list = lines_i_str.split(' \'')
|
|
95
|
+
subs = str(line_i_list[1]).split(':')
|
|
96
|
+
if len(subs) > 1:
|
|
97
|
+
# TODO 空格区分有用和无用,目前cookie的value中会有包含空格的情况, 不删除
|
|
98
|
+
header[subs[0]] = subs[1].replace(
|
|
99
|
+
'\'', '').replace('\\\n', '').replace(' ', '')
|
|
100
|
+
else:
|
|
101
|
+
header[subs[0]] = ''
|
|
102
|
+
elif '--data-raw' in lines_i_str or '--data' in lines_i_str:
|
|
103
|
+
line_i_list = lines_i_str.replace(' $',' ').split(' \'') # TODO 有$符号,split会失败,这样解决会出现被错误替换的问题
|
|
104
|
+
if len(line_i_list) > 1:
|
|
105
|
+
curl_data = line_i_list[1]
|
|
106
|
+
else:
|
|
107
|
+
curl_data = line_i_list[0]
|
|
108
|
+
req_data['body'] = curl_data.replace(
|
|
109
|
+
'\'', '').replace(' ', '').replace('\\\n', '').replace('\n', '')
|
|
110
|
+
|
|
111
|
+
if not req_data.get('method'):
|
|
112
|
+
req_data['method'] = 'post'
|
|
113
|
+
|
|
114
|
+
req_data['header'] = header
|
|
115
|
+
if not req_data.get('method'):
|
|
116
|
+
req_data['method'] = 'get'
|
|
117
|
+
|
|
118
|
+
return req_data
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
from http_content_parser.curl_parser import CurlParser
|
|
5
|
+
import yaml
|
|
6
|
+
from http_content_parser.req_data import ReqData
|
|
7
|
+
from http_content_parser.swagger2_parser import Swagger2Parser
|
|
8
|
+
from http_content_parser.openapi_parser import OpenApiParser
|
|
9
|
+
from http_content_parser.postman_parser import parse_postman
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GenerateApiFile():
|
|
13
|
+
|
|
14
|
+
def __init__(self) -> None:
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
def produce_api_yaml_for_postman(self, json_dict, yaml_file):
|
|
18
|
+
api_infos = parse_postman(json_dict)
|
|
19
|
+
for api_info in api_infos:
|
|
20
|
+
req_data = ReqData()
|
|
21
|
+
req_data.path = api_info['path']
|
|
22
|
+
req_data.header = json.dumps(api_info['header'])
|
|
23
|
+
req_data.body = api_info['body']
|
|
24
|
+
req_data.query_param = json.dumps(api_info['query_param'])
|
|
25
|
+
req_data.original_url = api_info['url']
|
|
26
|
+
req_data.method = api_info['method'].lower()
|
|
27
|
+
req_data.temp_api_label = self.convert_swagger2_path(
|
|
28
|
+
api_info['path'].split('/'), '_').replace('{', '').replace('}', '') + "_" + api_info['method'].lower()
|
|
29
|
+
self.write_api_content_to_yaml(yaml_file, req_data)
|
|
30
|
+
|
|
31
|
+
def produce_api_yaml_for_curl(self, curl_file, yaml_file, curl_filter=None):
|
|
32
|
+
curl_parser = CurlParser()
|
|
33
|
+
with open(curl_file, 'rt') as f:
|
|
34
|
+
lines = f.readlines()
|
|
35
|
+
line_num_array = curl_parser.get_curl_line_num_scope(lines=lines)
|
|
36
|
+
for r in line_num_array:
|
|
37
|
+
res_dict = curl_parser.split_curl_to_struct(
|
|
38
|
+
lines, r[0], r[1], curl_filter)
|
|
39
|
+
template = ReqData(dd=res_dict)
|
|
40
|
+
split_url = curl_parser.split_url(template.original_url, '_')
|
|
41
|
+
template.temp_api_label = self.replace_api_label_chars(
|
|
42
|
+
split_url['url_path']) + template.method
|
|
43
|
+
template.header = json.dumps(template.header)
|
|
44
|
+
template.query_param = json.dumps(split_url['url_params'])
|
|
45
|
+
split_url_origin = curl_parser.split_url(
|
|
46
|
+
template.original_url, '/')
|
|
47
|
+
template.path = split_url_origin['url_path'][:-1]
|
|
48
|
+
self.write_api_content_to_yaml(yaml_file, template)
|
|
49
|
+
|
|
50
|
+
def produce_api_yaml_for_swagger2(self, swagger2_dict, yaml_file):
|
|
51
|
+
swagger_parser = Swagger2Parser(swagger2_dict)
|
|
52
|
+
api_dict = swagger_parser.get_swagger_api_info()
|
|
53
|
+
if not api_dict:
|
|
54
|
+
print('check your swagger json')
|
|
55
|
+
return
|
|
56
|
+
for path, path_info in api_dict.items():
|
|
57
|
+
req_data = ReqData()
|
|
58
|
+
req_data.path = self.convert_swagger2_path(
|
|
59
|
+
path.split('/')[:-1], '/')
|
|
60
|
+
req_data.temp_api_label = self.convert_swagger2_path(
|
|
61
|
+
path.split('/'), '_').replace('{', '').replace('}', '')
|
|
62
|
+
req_data.method = path.split('/')[-1]
|
|
63
|
+
req_data.query_param = json.dumps(path_info['query_param'])
|
|
64
|
+
req_data.path_param = json.dumps(path_info['path_param'])
|
|
65
|
+
req_data.response = json.dumps(path_info.get('response', {}))
|
|
66
|
+
# swagger中body第一层和第二层key重复,只取第二层后的数据
|
|
67
|
+
for _, v in path_info['body_param'].items():
|
|
68
|
+
req_data.body = json.dumps(v)
|
|
69
|
+
self.write_api_content_to_yaml(yaml_file, req_data)
|
|
70
|
+
|
|
71
|
+
def produce_api_yaml_for_openapi3(self, openapi_dict, yaml_file):
|
|
72
|
+
if not openapi_dict:
|
|
73
|
+
print('openapi dict is null')
|
|
74
|
+
return
|
|
75
|
+
parser = OpenApiParser(openapi_dict)
|
|
76
|
+
api_dict = parser.get_open_api_info()
|
|
77
|
+
if not api_dict:
|
|
78
|
+
print('check your swagger json')
|
|
79
|
+
return
|
|
80
|
+
for path, path_info in api_dict.items():
|
|
81
|
+
req_data = ReqData()
|
|
82
|
+
req_data.path = self.convert_swagger2_path(
|
|
83
|
+
path.split('/')[:-1], '/')
|
|
84
|
+
req_data.temp_api_label = self.convert_swagger2_path(
|
|
85
|
+
path.split('/'), '_').replace('{', '').replace('}', '')
|
|
86
|
+
req_data.method = path.split('/')[-1]
|
|
87
|
+
req_data.query_param = json.dumps(path_info['query_param'])
|
|
88
|
+
req_data.path_param = json.dumps(path_info['path_param'])
|
|
89
|
+
req_data.response = json.dumps(path_info.get('response', {}))
|
|
90
|
+
req_data.body = json.dumps(path_info['body_param'])
|
|
91
|
+
self.write_api_content_to_yaml(yaml_file, req_data)
|
|
92
|
+
|
|
93
|
+
def convert_swagger2_path(self, path_list, split_char):
|
|
94
|
+
if not path_list:
|
|
95
|
+
return ''
|
|
96
|
+
url_path = ''
|
|
97
|
+
for u in path_list:
|
|
98
|
+
if u:
|
|
99
|
+
url_path += u + split_char
|
|
100
|
+
return url_path[:-1]
|
|
101
|
+
|
|
102
|
+
def replace_api_label_chars(self, string):
|
|
103
|
+
pattern = r'[+@?=.]' # 定义要匹配的特殊字符模式
|
|
104
|
+
replacement = '_' # 替换为的字符串
|
|
105
|
+
|
|
106
|
+
new_string = re.sub(pattern, replacement, string)
|
|
107
|
+
return new_string
|
|
108
|
+
|
|
109
|
+
def write_api_content_to_yaml(self, file, template: ReqData):
|
|
110
|
+
api_obj = {}
|
|
111
|
+
yaml_obj = {}
|
|
112
|
+
with open(file, 'at') as f:
|
|
113
|
+
api_obj['original_url'] = template.original_url
|
|
114
|
+
api_obj['path'] = template.path
|
|
115
|
+
api_obj['query_param'] = template.query_param
|
|
116
|
+
api_obj['path_param'] = template.path_param
|
|
117
|
+
api_obj['header'] = template.header
|
|
118
|
+
api_obj['body'] = template.body
|
|
119
|
+
api_obj['method'] = template.method
|
|
120
|
+
api_obj['response'] = template.response
|
|
121
|
+
yaml_obj[template.temp_api_label] = api_obj
|
|
122
|
+
yaml.dump(yaml_obj, f)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
|
|
2
|
+
class OpenApiParser(object):
|
|
3
|
+
def __init__(self, openapi_json_dict) -> None:
|
|
4
|
+
self.openapi_dict = openapi_json_dict
|
|
5
|
+
self.schema_ref_list = []
|
|
6
|
+
|
|
7
|
+
def parse_request_body(self, api_info):
|
|
8
|
+
body_param_dict = {}
|
|
9
|
+
api_content_type = ''
|
|
10
|
+
if api_info.get('requestBody'):
|
|
11
|
+
request_body = api_info['requestBody']
|
|
12
|
+
for content_type, schema in request_body['content'].items():
|
|
13
|
+
api_content_type = content_type
|
|
14
|
+
for k, v in schema['schema']['properties'].items():
|
|
15
|
+
if v.get('items'):
|
|
16
|
+
if v['items'].get('$ref'):
|
|
17
|
+
schema_ref = v['items']['$ref'].split('/')[-1]
|
|
18
|
+
body_param_dict[k] = self.parse_body_schema(
|
|
19
|
+
schema_ref)
|
|
20
|
+
self.schema_ref_list = []
|
|
21
|
+
else:
|
|
22
|
+
body_param_dict[k] = [
|
|
23
|
+
v.get('type', 'unknown_type')]
|
|
24
|
+
|
|
25
|
+
else:
|
|
26
|
+
body_param_dict[k] = v.get('type', 'unknown_type')
|
|
27
|
+
return body_param_dict, api_content_type
|
|
28
|
+
|
|
29
|
+
def parse_parameters(self, params):
|
|
30
|
+
path_param_dict = {}
|
|
31
|
+
body_param_dict = {}
|
|
32
|
+
query_param_dict = {}
|
|
33
|
+
form_data_param_dict = {}
|
|
34
|
+
for param in params:
|
|
35
|
+
if isinstance(param, dict):
|
|
36
|
+
if param.get('in') == 'path':
|
|
37
|
+
path_param_dict[param['name']] = param['schema']['type']
|
|
38
|
+
elif param.get('in') == 'query':
|
|
39
|
+
query_param_dict[param['name']] = param['schema']['type']
|
|
40
|
+
elif param.get('in') == 'formData':
|
|
41
|
+
form_data_param_dict[param['name']
|
|
42
|
+
] = param['schema']['type']
|
|
43
|
+
else:
|
|
44
|
+
print('error: parameters in type error')
|
|
45
|
+
|
|
46
|
+
return body_param_dict, path_param_dict, query_param_dict, form_data_param_dict
|
|
47
|
+
|
|
48
|
+
def parse_body_schema(self, param_schema_ref):
|
|
49
|
+
self.schema_ref_list.append(param_schema_ref)
|
|
50
|
+
schema_dict = {}
|
|
51
|
+
schema_info = self.openapi_dict['components']['schemas'].get(
|
|
52
|
+
param_schema_ref)
|
|
53
|
+
if schema_info:
|
|
54
|
+
properties = schema_info.get('properties')
|
|
55
|
+
if isinstance(properties, dict):
|
|
56
|
+
for param, param_type_dict in properties.items():
|
|
57
|
+
if param_type_dict.get('$ref'):
|
|
58
|
+
schema_ref_name = param_type_dict['$ref'].split(
|
|
59
|
+
'/')[-1]
|
|
60
|
+
if schema_ref_name not in self.schema_ref_list:
|
|
61
|
+
self.schema_ref_list.append(schema_ref_name)
|
|
62
|
+
sub_param_value = self.parse_body_schema(
|
|
63
|
+
schema_ref_name)
|
|
64
|
+
if param_type_dict.get('type') == 'array':
|
|
65
|
+
schema_dict[param] = [sub_param_value]
|
|
66
|
+
else:
|
|
67
|
+
schema_dict[param] = sub_param_value
|
|
68
|
+
else:
|
|
69
|
+
if param_type_dict.get('type') == 'array':
|
|
70
|
+
schema_dict[param] = [{}]
|
|
71
|
+
else:
|
|
72
|
+
schema_dict[param] = {}
|
|
73
|
+
elif param_type_dict.get('items'):
|
|
74
|
+
if param_type_dict['items'].get('$ref'):
|
|
75
|
+
schema_item_ref_name = param_type_dict['items']['$ref'].split(
|
|
76
|
+
'/')[-1]
|
|
77
|
+
if schema_item_ref_name not in self.schema_ref_list:
|
|
78
|
+
self.schema_ref_list.append(
|
|
79
|
+
schema_item_ref_name)
|
|
80
|
+
sub_param_value = self.parse_body_schema(
|
|
81
|
+
schema_item_ref_name)
|
|
82
|
+
schema_dict[param] = [sub_param_value]
|
|
83
|
+
else:
|
|
84
|
+
schema_dict[param] = [{}]
|
|
85
|
+
else:
|
|
86
|
+
schema_dict[param] = [param_type_dict['type']]
|
|
87
|
+
else:
|
|
88
|
+
if param_type_dict.get('type'):
|
|
89
|
+
schema_dict[param] = param_type_dict['type']
|
|
90
|
+
else:
|
|
91
|
+
schema_dict[param] = param_type_dict
|
|
92
|
+
return schema_dict
|
|
93
|
+
|
|
94
|
+
def parse_response(self, res_dict):
|
|
95
|
+
res = {}
|
|
96
|
+
# openapi's schema position
|
|
97
|
+
content = res_dict['200']['content']
|
|
98
|
+
schema = {}
|
|
99
|
+
for _, c_v in content.items():
|
|
100
|
+
schema = c_v['schema']
|
|
101
|
+
if schema.get("$ref"):
|
|
102
|
+
schema_ref_name = schema['$ref'].split('/')[-1]
|
|
103
|
+
res = self.parse_body_schema(schema_ref_name)
|
|
104
|
+
self.schema_ref_list = []
|
|
105
|
+
return res
|
|
106
|
+
elif schema.get("items"):
|
|
107
|
+
schema_ref_name = schema['items']['$ref'].split('/')[-1]
|
|
108
|
+
# TODO array schema: [{}] or {} ?
|
|
109
|
+
res = self.parse_body_schema(schema_ref_name)
|
|
110
|
+
self.schema_ref_list = []
|
|
111
|
+
return res
|
|
112
|
+
else:
|
|
113
|
+
for _, v in schema.items():
|
|
114
|
+
if isinstance(v, list):
|
|
115
|
+
for item_dict in v:
|
|
116
|
+
if isinstance(item_dict, dict):
|
|
117
|
+
for item_k, item_v in item_dict.items():
|
|
118
|
+
if item_k == '$ref':
|
|
119
|
+
schema_ref_name = item_v.split('/')[-1]
|
|
120
|
+
res.update(
|
|
121
|
+
self.parse_body_schema(schema_ref_name))
|
|
122
|
+
self.schema_ref_list = []
|
|
123
|
+
if item_k == 'properties':
|
|
124
|
+
for k2, v2 in item_v.items():
|
|
125
|
+
if v2.get('$ref'):
|
|
126
|
+
schema_ref_name = v2['$ref'].split(
|
|
127
|
+
'/')[-1]
|
|
128
|
+
res[k2] = self.parse_body_schema(
|
|
129
|
+
schema_ref_name)
|
|
130
|
+
self.schema_ref_list = []
|
|
131
|
+
|
|
132
|
+
return res
|
|
133
|
+
|
|
134
|
+
def get_open_api_info(self):
|
|
135
|
+
result = {}
|
|
136
|
+
base_path = self.openapi_dict['servers'][0]['url']
|
|
137
|
+
for path, api_infos in (self.openapi_dict['paths']).items():
|
|
138
|
+
for path_method, api_info in api_infos.items():
|
|
139
|
+
_path_param = {}
|
|
140
|
+
_query_param = {}
|
|
141
|
+
_form_param = {}
|
|
142
|
+
_body_param = {}
|
|
143
|
+
_api_response = {}
|
|
144
|
+
if api_info.get('parameters'):
|
|
145
|
+
api_param = self.parse_parameters(api_info['parameters'])
|
|
146
|
+
_path_param = api_param[1]
|
|
147
|
+
_query_param = api_param[2]
|
|
148
|
+
_form_param = api_param[3]
|
|
149
|
+
if api_info.get('requestBody'):
|
|
150
|
+
body_result = self.parse_request_body(api_info)
|
|
151
|
+
_body_param = body_result[0]
|
|
152
|
+
# content_type = result[1]
|
|
153
|
+
if api_info.get('responses'):
|
|
154
|
+
_api_response = self.parse_response(api_info['responses'])
|
|
155
|
+
|
|
156
|
+
result[f'{base_path}{path}/{path_method}'] = {'path_param': _path_param,
|
|
157
|
+
'query_param': _query_param, 'form_param': _form_param, 'body_param': _body_param, 'response': _api_response}
|
|
158
|
+
|
|
159
|
+
return result
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
api_info_list = []
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def parse_postman(json_file):
|
|
9
|
+
# TODO 如果postman中有变量,则无法解析变量的值.
|
|
10
|
+
items = json_file.get('item')
|
|
11
|
+
if items:
|
|
12
|
+
for item in items:
|
|
13
|
+
if item.get('item'):
|
|
14
|
+
parse_postman(item)
|
|
15
|
+
else:
|
|
16
|
+
api_info = {}
|
|
17
|
+
if not item.get('request'):
|
|
18
|
+
continue
|
|
19
|
+
postman_request = item['request']
|
|
20
|
+
api_info['method'] = postman_request['method']
|
|
21
|
+
api_info['header'] = {}
|
|
22
|
+
for hs in postman_request['header']:
|
|
23
|
+
api_info['header'][hs['key']] = hs['value']
|
|
24
|
+
api_info['url'] = postman_request['url']['raw']
|
|
25
|
+
if not postman_request['url'].get('path'):
|
|
26
|
+
continue
|
|
27
|
+
api_info['path'] = "/".join(postman_request['url']['path'])
|
|
28
|
+
api_info['query_param'] = {}
|
|
29
|
+
if postman_request['url'].get('query'):
|
|
30
|
+
for qs in postman_request['url']['query']:
|
|
31
|
+
api_info['query_param'][qs['key']] = qs['value']
|
|
32
|
+
api_info['body'] = {}
|
|
33
|
+
if postman_request.get('body'):
|
|
34
|
+
temp = postman_request['body'][postman_request['body']['mode']]
|
|
35
|
+
if isinstance(temp, str):
|
|
36
|
+
# \\n 只会出现在value中,一般是用户自己定义的
|
|
37
|
+
temp = temp.replace("\\n", "").replace("\n", "")
|
|
38
|
+
if temp:
|
|
39
|
+
# beautify json string
|
|
40
|
+
temp = json.loads(temp)
|
|
41
|
+
temp = json.dumps(temp)
|
|
42
|
+
api_info['body'] = temp
|
|
43
|
+
api_info_list.append(api_info)
|
|
44
|
+
return api_info_list
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
__author__ = maxsulei
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ReqData(object):
|
|
9
|
+
|
|
10
|
+
def __init__(self, dd=None):
|
|
11
|
+
if dd and isinstance(dd, dict):
|
|
12
|
+
self.__path = dd.get('path', '')
|
|
13
|
+
self.__method = dd.get('method', '')
|
|
14
|
+
self.__body = dd.get('body', {})
|
|
15
|
+
self.__header = dd.get('header', {})
|
|
16
|
+
self.__query_param = dd.get('query_param', {})
|
|
17
|
+
self.__path_param = dd.get('path_param', {})
|
|
18
|
+
self.__original_url = dd.get('original_url', '')
|
|
19
|
+
self.__temp_api_label = dd.get('temp_api_label', '')
|
|
20
|
+
self.__host = ''
|
|
21
|
+
self.__response = dd.get('response', {})
|
|
22
|
+
else:
|
|
23
|
+
self.__host = ''
|
|
24
|
+
self.__path = ''
|
|
25
|
+
self.__method = ''
|
|
26
|
+
self.__body = {}
|
|
27
|
+
self.__header = {}
|
|
28
|
+
self.__query_param = {}
|
|
29
|
+
self.__path_param = {}
|
|
30
|
+
self.__original_url = ''
|
|
31
|
+
self.__temp_api_label = ''
|
|
32
|
+
self.__response = {}
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def temp_api_label(self):
|
|
36
|
+
return self.__temp_api_label
|
|
37
|
+
|
|
38
|
+
@temp_api_label.setter
|
|
39
|
+
def temp_api_label(self, value):
|
|
40
|
+
self.__temp_api_label = value
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def url(self):
|
|
44
|
+
return self.__host + self.__path
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def original_url(self):
|
|
48
|
+
return self.__original_url
|
|
49
|
+
|
|
50
|
+
@original_url.setter
|
|
51
|
+
def original_url(self, value):
|
|
52
|
+
self.__original_url = value
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def method(self):
|
|
56
|
+
return self.__method
|
|
57
|
+
|
|
58
|
+
@method.setter
|
|
59
|
+
def method(self, value):
|
|
60
|
+
self.__method = value
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def body(self):
|
|
64
|
+
return self.__body
|
|
65
|
+
|
|
66
|
+
@body.setter
|
|
67
|
+
def body(self, value):
|
|
68
|
+
self.__body = value
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def header(self):
|
|
72
|
+
return self.__header
|
|
73
|
+
|
|
74
|
+
@header.setter
|
|
75
|
+
def header(self, value):
|
|
76
|
+
self.__header = value
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def host(self):
|
|
80
|
+
return self.__host
|
|
81
|
+
|
|
82
|
+
@host.setter
|
|
83
|
+
def host(self, value):
|
|
84
|
+
self.__host = value
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def path(self):
|
|
88
|
+
return self.__path
|
|
89
|
+
|
|
90
|
+
@path.setter
|
|
91
|
+
def path(self, value):
|
|
92
|
+
self.__path = value
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def query_param(self):
|
|
96
|
+
return self.__query_param
|
|
97
|
+
|
|
98
|
+
@query_param.setter
|
|
99
|
+
def query_param(self, value):
|
|
100
|
+
self.__query_param = value
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def path_param(self):
|
|
104
|
+
return self.__path_param
|
|
105
|
+
|
|
106
|
+
@path_param.setter
|
|
107
|
+
def path_param(self, value):
|
|
108
|
+
self.__path_param = value
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def response(self):
|
|
112
|
+
return self.__response
|
|
113
|
+
|
|
114
|
+
@response.setter
|
|
115
|
+
def response(self, value):
|
|
116
|
+
self.__response = value
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
|
2
|
+
class Swagger2Parser(object):
|
|
3
|
+
def __init__(self, swagger_json_dict) -> None:
|
|
4
|
+
self.swagger_dict = swagger_json_dict
|
|
5
|
+
self.schema_ref_list = []
|
|
6
|
+
|
|
7
|
+
def parse_parameters(self, params):
|
|
8
|
+
path_param_dict = {}
|
|
9
|
+
body_param_dict = {}
|
|
10
|
+
query_param_dict = {}
|
|
11
|
+
form_data_param_dict = {}
|
|
12
|
+
for param in params:
|
|
13
|
+
if isinstance(param, dict):
|
|
14
|
+
if param.get('in') == 'path':
|
|
15
|
+
path_param_dict[param['name']] = param['type']
|
|
16
|
+
elif param.get('in') == 'body':
|
|
17
|
+
if param.get('schema'):
|
|
18
|
+
schema_ref = param['schema']['$ref'].split('/')[-1]
|
|
19
|
+
body_param_dict[param['name']
|
|
20
|
+
] = self.parse_body_schema(schema_ref)
|
|
21
|
+
self.schema_ref_list = []
|
|
22
|
+
elif param.get('in') == 'query':
|
|
23
|
+
query_param_dict[param['name']] = param['type']
|
|
24
|
+
elif param.get('in') == 'formData':
|
|
25
|
+
form_data_param_dict[param['name']] = param['type']
|
|
26
|
+
else:
|
|
27
|
+
print('error: parameters in type error')
|
|
28
|
+
|
|
29
|
+
return body_param_dict, path_param_dict, query_param_dict, form_data_param_dict
|
|
30
|
+
|
|
31
|
+
def parse_body_schema(self, param_schema_ref):
|
|
32
|
+
self.schema_ref_list.append(param_schema_ref)
|
|
33
|
+
schema_dict = {}
|
|
34
|
+
schema_info = self.swagger_dict['definitions'].get(param_schema_ref)
|
|
35
|
+
if schema_info:
|
|
36
|
+
properties = schema_info.get('properties')
|
|
37
|
+
if isinstance(properties, dict):
|
|
38
|
+
for param, param_type_dict in properties.items():
|
|
39
|
+
if param_type_dict.get('$ref'):
|
|
40
|
+
schema_ref_name = param_type_dict['$ref'].split(
|
|
41
|
+
'/')[-1]
|
|
42
|
+
# prevent infinite loop
|
|
43
|
+
if schema_ref_name not in self.schema_ref_list:
|
|
44
|
+
self.schema_ref_list.append(schema_ref_name)
|
|
45
|
+
sub_param_value = self.parse_body_schema(
|
|
46
|
+
schema_ref_name)
|
|
47
|
+
if param_type_dict.get('type') == 'array':
|
|
48
|
+
schema_dict[param] = [sub_param_value]
|
|
49
|
+
else:
|
|
50
|
+
schema_dict[param] = sub_param_value
|
|
51
|
+
else:
|
|
52
|
+
if param_type_dict.get('type') == 'array':
|
|
53
|
+
schema_dict[param] = [{}]
|
|
54
|
+
else:
|
|
55
|
+
schema_dict[param] = {}
|
|
56
|
+
elif param_type_dict.get('items'):
|
|
57
|
+
if param_type_dict['items'].get('$ref'):
|
|
58
|
+
schema_item_ref_name = param_type_dict['items']['$ref'].split(
|
|
59
|
+
'/')[-1]
|
|
60
|
+
if schema_item_ref_name not in self.schema_ref_list:
|
|
61
|
+
self.schema_ref_list.append(
|
|
62
|
+
schema_item_ref_name)
|
|
63
|
+
sub_param_value = self.parse_body_schema(
|
|
64
|
+
schema_item_ref_name)
|
|
65
|
+
schema_dict[param] = [sub_param_value]
|
|
66
|
+
else:
|
|
67
|
+
schema_dict[param] = [{}]
|
|
68
|
+
else:
|
|
69
|
+
schema_dict[param] = [param_type_dict['type']]
|
|
70
|
+
else:
|
|
71
|
+
if param_type_dict.get('type'):
|
|
72
|
+
schema_dict[param] = param_type_dict['type']
|
|
73
|
+
else:
|
|
74
|
+
schema_dict[param] = param_type_dict
|
|
75
|
+
return schema_dict
|
|
76
|
+
|
|
77
|
+
def parse_response(self, res_dict):
|
|
78
|
+
res = {}
|
|
79
|
+
if res_dict['200'].get('schema'):
|
|
80
|
+
schema = res_dict['200']['schema']
|
|
81
|
+
if schema.get("$ref"):
|
|
82
|
+
schema_ref_name = schema['$ref'].split('/')[-1]
|
|
83
|
+
res = self.parse_body_schema(schema_ref_name)
|
|
84
|
+
self.schema_ref_list = []
|
|
85
|
+
return res
|
|
86
|
+
elif schema.get("items"):
|
|
87
|
+
schema_ref_name = schema['items']['$ref'].split('/')[-1]
|
|
88
|
+
# TODO array schema: [{}] or {} ?
|
|
89
|
+
res = self.parse_body_schema(schema_ref_name)
|
|
90
|
+
self.schema_ref_list = []
|
|
91
|
+
return res
|
|
92
|
+
else:
|
|
93
|
+
for _, v in schema.items():
|
|
94
|
+
if isinstance(v, list):
|
|
95
|
+
for item_dict in v:
|
|
96
|
+
if isinstance(item_dict, dict):
|
|
97
|
+
for item_k, item_v in item_dict.items():
|
|
98
|
+
if item_k == '$ref':
|
|
99
|
+
schema_ref_name = item_v.split('/')[-1]
|
|
100
|
+
res.update(
|
|
101
|
+
self.parse_body_schema(schema_ref_name))
|
|
102
|
+
self.schema_ref_list = []
|
|
103
|
+
if item_k == 'properties':
|
|
104
|
+
for k2, v2 in item_v.items():
|
|
105
|
+
if v2.get('$ref'):
|
|
106
|
+
schema_ref_name = v2['$ref'].split(
|
|
107
|
+
'/')[-1]
|
|
108
|
+
res[k2] = self.parse_body_schema(
|
|
109
|
+
schema_ref_name)
|
|
110
|
+
self.schema_ref_list = []
|
|
111
|
+
|
|
112
|
+
else:
|
|
113
|
+
print('response dont have schema')
|
|
114
|
+
return res
|
|
115
|
+
|
|
116
|
+
def get_swagger_api_info(self):
|
|
117
|
+
result = {}
|
|
118
|
+
base_path = self.swagger_dict['basePath'].replace('/', '')
|
|
119
|
+
for path, api_infos in (self.swagger_dict['paths']).items():
|
|
120
|
+
for path_method, api_info in api_infos.items():
|
|
121
|
+
if api_info.get('parameters'):
|
|
122
|
+
api_param = self.parse_parameters(api_info['parameters'])
|
|
123
|
+
api_res = self.parse_response(api_info['responses'])
|
|
124
|
+
result[f'{base_path}{path}/{path_method}'] = {'path_param': api_param[1],
|
|
125
|
+
'query_param': api_param[2], 'form_param': api_param[3], 'body_param': api_param[0], 'response': api_res}
|
|
126
|
+
else:
|
|
127
|
+
result[f'{base_path}{path}/{path_method}'] = {'path_param': {},
|
|
128
|
+
'query_param': {}, 'form_param': {}, 'body_param': {}}
|
|
129
|
+
|
|
130
|
+
return result
|