diff options
author | Anton Tananaev <anton.tananaev@gmail.com> | 2016-12-14 17:12:21 +1300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-14 17:12:21 +1300 |
commit | 1a3b3b1dd599a2f00a19987e7db4e522b8a62fc5 (patch) | |
tree | 0969ee067cab5887c781f2d1909040e5c71dbdcc /tools | |
parent | c337d7b7c332b8b12c20cd7bc1b607547f1a9bb1 (diff) | |
parent | 29b07707b485ea38dd2af13f89dbd2d37dc61b45 (diff) | |
download | traccar-server-1a3b3b1dd599a2f00a19987e7db4e522b8a62fc5.tar.gz traccar-server-1a3b3b1dd599a2f00a19987e7db4e522b8a62fc5.tar.bz2 traccar-server-1a3b3b1dd599a2f00a19987e7db4e522b8a62fc5.zip |
Merge pull request #2681 from sunhoww/update_swagger
Update swagger documentation
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/swagger2html.py | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/tools/swagger2html.py b/tools/swagger2html.py new file mode 100755 index 000000000..a3488835c --- /dev/null +++ b/tools/swagger2html.py @@ -0,0 +1,354 @@ +#!/usr/bin/python + +import sys, argparse, json, re + +def handleException(etype, e=None): + if etype == 'KeyError': + print "Error: Required property {} not found".format(e) + elif etype == 'IOError': + print "Error ({}): {}".format(e.errno, e.strerror) + elif etype == 'ValueError': + print "Error: Unable to parse input as JSON" + elif etype == 'Custom': + print e + sys.exit(1) + +def get_json(filename): + try: + with open(filename) as json_file: + json_data = json.load(json_file) + return json_data + except IOError as e: + handleException('IOError', e) + except ValueError: + handleException('ValueError') + except: + print "Unexpected error: {}".format(sys.exc_info()[0]) + raise + +def write_file(filename, body): + try: + with open(filename, 'w') as md_file: + md_file.write(body) + except IOError as e: + handleException('IOError', e) + +def make_header(json_data): + try: + if not 'swagger' in json_data: + raise KeyError + info = json_data['info'] + md = "<h1>{}</h1>\n".format(info['title']) + md += "<p>Version: {}</p>\n".format(info['version']) + if 'license' in info: + md += "<p>License: " + license = info['license'] + if 'url' in license: + md += '<a href="{}">{}</a>'.format(license['url'], license['name']) + else: + md += license['name'] + md += '</p>\n' + if 'contact' in info: + contact = info['contact'] + if 'name' in contact or 'email' in contact: + md += '<p>Contact: ' + if not 'name' in contact: + md += '<a href="mailto:{0}">{0}</a>'.format(contact['email']) + elif not 'email' in contact: + md += contact['name'] + else: + md += '{0} <<a href="mailto:{1}">{1}</a>'.format(contact['name'], contact['email']) + md += ' \n' + if 'url' in contact: + md += "<p>Website: {}</p>\n".format(contact['url']) + if 'termsOfService' in info: + md += '<p>Terms of Service: {}</p>\n'.format(info['termsOfService']) + if 'host' in json_data: + md += '<p>Base URL: ' + base = json_data['host'] + if 'basePath' in json_data: + base += json_data['basePath'] + else: + base += '/' + if 'schemes' in json_data: + md += (', ').join(map( + lambda x: '<a href="{0}://{1}">{0}://{1}</a>'.format(x, base), + json_data['schemes'] + )) + else: + md += '<a href="{0}">{0}</a>'.format(base) + md += '</p>\n' + if 'description' in info: + md += '<p>Description: {}</p>\n'.format(info['description']) + md += '\n' + return md + except KeyErrori as e: + handleException('KeyError', e) + +def make_ref(ref): + href = ref.split('/')[1:] + return '<a href="#{}">{}</a>'.format('_'.join(href), href[-1]) + +def get_ref(ref, raw): + keys = ref.split('/') + return raw[keys[1]][keys[2]] + +def make_html(s): + reg = re.compile(r"[*_]{3}(.+?)[*_]{3}") + s = reg.sub(r"<strong><em>\1</em></strong>", s) + reg = re.compile(r"[*_]{2}(.+?)[*_]{2}") + s = reg.sub(r"<strong>\1</strong>", s) + reg = re.compile(r"[*_](.+?)[*_]") + s = reg.sub(r"<em>\1</em>", s) + reg = re.compile(r"\`(.+?)\`") + s = reg.sub(r"<code>\1</code>", s) + return s + +def make_table(data): + md = '<table class="table-bordered">\n' + md += ' <thead>\n' + md += ' <tr>\n' + for col in data[0]: + md += ' <td>{}</td>\n'.format(col) + md += ' </tr>\n' + md += ' </thead>\n' + md += ' <tbody>\n' + for row in data[1:]: + md += ' <tr>\n' + for cell in row: + md += ' <td>{}</td>\n'.format(cell) + md += ' </tr>\n' + md += ' </tbody>\n' + md += '</table>\n' + return md + +def make_params_table(itemsraw, raw): + items = [] + for item in itemsraw: + if '$ref' in item: + items.append(get_ref(item['$ref'], raw)) + else: + items.append(item) + try: + fields = list(set([]).union(*map(lambda x: x.keys(), items))) + row = [ 'Name', 'ParamType' ] + if 'description' in fields: + row.append('Description') + if 'required' in fields: + row.append('Required') + if 'type' in fields: + row.append('DataType') + if 'schema' in fields: + row.append('Schema') + table = [ row ] + for item in items: + row = [ "<em>{}</em>".format(item['name']), item['in'] ] + if 'description' in fields: + if 'description' in item: + row.append(make_html(item['description'])) + else: + row.append('') + if 'required' in fields: + required = 'False' + if 'required' in item and item['required']: + required = "<strong>True</strong>" + row.append(required) + if 'type' in fields: + type = '' + if 'type' in item: + if item['type'] == 'array': + type = "[ <em>{}</em> ]".format(item['items']['type']) + else: + type = item['type'] + if 'format' in item: + type += " ({})".format(item['format']) + type = "<em>{}</em>".format(type) + row.append(type) + if 'schema' in fields: + if 'schema' in item: + if '$ref' in item['schema']: + row.append(make_ref(item['schema']['$ref'])) + else: + row.append('') + table.append(row) + return make_table(table) + except KeyError as e: + handleException('KeyError', e) + +def make_responses_table(responses): + try: + fields = list( + set([]).union(*map(lambda x: x.keys(), + map(lambda x: responses[x], responses.keys()) + )) + ) + row = [ 'Status Code', 'Description' ] + if 'headers' in fields: + row.append('Headers') + if 'schema' in fields: + row.append('Schema') + if 'examples' in fields: + row.append('Examples') + table = [ row ] + for key in sorted(responses): + response = responses[key] + row = [ "<em>{}</em>".format(key), make_html(response['description']) ] + if 'headers' in fields: + header = '' + if 'headers' in response: + hrow = [] + for header, h_obj in response['headers'].iteritems(): + hrow += "{} ({})".format(header, h_obj['type']) + if 'description' in h_obj: + hrow += ": {}".format(h_obj['description']) + header = ' \n'.join(hrow) + row.append(header) + if 'schema' in fields: + schema = '' + if 'schema' in response: + if '$ref' in response['schema']: + schema += make_ref(response['schema']['$ref']) + if 'type' in response['schema']: + if response['schema']['type'] == 'array': + if '$ref' in response['schema']['items']: + schema += make_ref(response['schema']['items']['$ref']) + schema = "[ {} ]".format(schema) + row.append(schema) + if 'examples' in fields: + if 'examples' in response: + row.append(response['examples']) + else: + row.append('') + table.append(row) + return make_table(table) + except KeyError as e: + handleException('KeyError', e) + +def make_paths(sections, json_data): + md = '<h2><a name="paths"></a>Paths</h2>\n' + for key in sorted(sections): + md += '<h3><a name="paths_{0}"></a>{0}</h3>\n'.format(key) + for section in sections[key]: + md += '<h4><a name="{}"></a><code>{}</code></h4>\n'.format( + section['href'], section['title'] + ) + operation = section['operation'] + if 'summary' in operation: + md += '<p>Summary: {}</p>\n'.format(make_html(operation['summary'])) + if 'description' in operation: + md += '<p>Description: {}</p>\n'.format(make_html(operation['description'])) + md += '<h5>Parameters</h5>\n' + if 'parameters' in operation and len(operation['parameters']) > 0: + md += make_params_table(operation['parameters'], json_data) + else: + md += "<p><em>None</em></p>\n" + md += '<h5>Responses</h5>\n' + md += make_responses_table(operation['responses']) + md += '\n' + md += '\n' + return md + +def make_contents(path_section, json_data): + md = '<h3>Contents</h3>\n' + md += '<ul>\n' + md += ' <li><a href="#paths">Paths</a>\n' + md += ' <ul>\n' + for key in sorted(path_section): + md += ' <li><a href="#paths_{0}">{0}</a>\n'.format(key) + md += ' <ul>\n' + for section in path_section[key]: + md += ' <li><a href="#{}">{}</a></li>\n'.format( + section['href'], section['title'] + ) + md += ' </ul>\n' + md += ' </li>\n' + md += ' </ul>\n' + md += ' </li>\n' + md += ' <li><a href="#definitions">Models</a>\n' + md += ' <ul>\n' + for key in sorted(json_data['definitions']): + md += ' <li><a href="#definitions_{0}">{0}</a></li>\n'.format(key) + md += ' </ul>\n' + md += ' </li>\n' + md += '</ul>\n' + return md + +def make_definitions(json_data): + md = '<h2><a name="definitions"></a>Models</h2>\n' + for name in sorted(json_data['definitions']): + md += '<h3><a name="definitions_{0}"></a>{0}</h3>\n'.format(name) + model = json_data['definitions'][name] + if 'properties' in model: + fields = list( + set(['type']).union( + *map(lambda x: x.keys(), + map(lambda x: model['properties'][x], model['properties'].keys()) + ) + ) + ) + row = [ 'Property', 'Type' ] + if 'description' in fields: + row.append('Description') + table = [ row ] + for key in sorted(model['properties']): + property = model['properties'][key] + row = [ "<em>{}</em>".format(key) ] + if 'type' in property: + type = property['type'] + if 'format' in property: + type += " ({})".format(property['format']) + row.append("<em>{}</em>".format(type)) + elif '$ref' in property: + row.append(make_ref(property['$ref'])) + else: + row.append('') + if 'description' in fields: + if 'description' in property: + row.append(make_html(property['description'])) + else: + row.append('') + table.append(row) + md += make_table(table) + return md + +def make_markdown(json_data): + path_sections = {} + for endpoint in json_data['paths']: + path_split = endpoint.split('/') + path_key = path_split[1] + if not path_key in path_sections: + path_sections[path_key] = [] + for method, operation in json_data['paths'][endpoint].iteritems(): + if 'operationId' in operation: + link = operation['operationId'] + else: + link = ''.join([ + c for c in endpoint if c not in ['/', '{', '}'] + ]) + path_sections[path_key].append({ + 'title': '{} {}'.format(method.upper(), endpoint), + 'href': 'paths_{}_{}'.format(link, method.upper()), + 'operation': operation + }) + md = make_header(json_data) + md += make_contents(path_sections, json_data) + md += make_paths(path_sections, json_data) + md += make_definitions(json_data) + return md + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('SPECFILE', help="path to swagger.json file") + parser.add_argument('OUTFILE', help="path to output HTML file") + args = parser.parse_args() + + marked_down = make_markdown(get_json(args.SPECFILE)) + + if args.OUTFILE: + write_file(args.OUTFILE, marked_down) + print " success: {}".format(args.OUTFILE) + else: + print marked_down + +if __name__ == '__main__': + main() |