generate_api_doc.py
3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import collections
import re
from django.core.management import BaseCommand
from django.urls.resolvers import get_resolver
import yaml
from yaml.scanner import ScannerError
from common.api_doc import (base_part, security_definitions, responses, definitions)
_mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG
def dict_representer(dumper, data):
return dumper.represent_dict(data.items())
def dict_constructor(loader, node):
return collections.OrderedDict(loader.construct_pairs(node))
yaml.add_representer(collections.OrderedDict, dict_representer)
yaml.add_constructor(_mapping_tag, dict_constructor)
def unify_url_path_format(string):
return '/%s' % re.sub(r'%\(([^/]+)\)s', lambda m: '{%s}' % m.group(1),
string)
DEFAULT_API_DOC = '''
summary: 未填写
responses:
200:
description: ok
'''
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('-o', '--output_file', help='文件名,用于存储文档')
def handle(self, *args, **kwargs):
urls = get_resolver()
api_doc_dct = {}
for view, pattern in urls.reverse_dict.items():
view_class = view.view_class
url_path, path_parameters = pattern[0][0]
url_path = unify_url_path_format(url_path)
if url_path not in ['/api/compare/settlement/v1', '/api/compare/v1']:
continue
url_path_paramters = getattr(view, 'parameters_doc', None)
if url_path_paramters:
url_path_paramters = yaml.load(url_path_paramters)
else:
url_path_paramters = [{
'in': 'path',
'name': parameter,
'required': True,
'schema': {
'type': 'string'
}
} for parameter in path_parameters]
api_doc_dct[url_path] = {}
if url_path_paramters:
api_doc_dct[url_path]['parameters'] = url_path_paramters
for method in view_class.http_method_names:
method_handler = getattr(view_class, method, None)
doc = getattr(method_handler, 'openapi_doc', None)
if not method_handler or (method == 'options' and not doc):
continue
try:
doc = yaml.load(doc or DEFAULT_API_DOC)
except ScannerError as err:
raise Exception(
'failed to load doc: """%s"""\nerr: %s' % (doc, err))
# if doc.get('parameters'):
# for parameter in doc['parameters']:
# if parameter['name'] in path_parameters:
# doc['parameters'].pop(parameter)
api_doc_dct[url_path][method] = doc
doc_dct = yaml.load(base_part)
doc_dct['paths'] = api_doc_dct
doc_dct['securityDefinitions'] = yaml.load(security_definitions)
doc_dct['responses'] = yaml.load(responses)
doc_dct['definitions'] = yaml.load(definitions)
doc_str = yaml.dump(
doc_dct, default_flow_style=False, allow_unicode=True)
if kwargs.get('output_file'):
with open(kwargs['output_file'], 'w') as f:
f.write(doc_str)
self.stdout.write(
self.style.SUCCESS('api doc generated succssfully: %s' %
kwargs['output_file']))
else:
self.stdout.write(doc_str)