From a04c318ef92623478cf07b2f9ffca90b0f6507ad Mon Sep 17 00:00:00 2001 From: Sun Howwrongbum Date: Tue, 13 Dec 2016 16:43:31 +0530 Subject: Add script to generate HTML from swagger.json - #2680 --- tools/swagger2html.py | 354 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 354 insertions(+) create mode 100755 tools/swagger2html.py 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 = "

{}

\n".format(info['title']) + md += "

Version: {}

\n".format(info['version']) + if 'license' in info: + md += "

License: " + license = info['license'] + if 'url' in license: + md += '{}'.format(license['url'], license['name']) + else: + md += license['name'] + md += '

\n' + if 'contact' in info: + contact = info['contact'] + if 'name' in contact or 'email' in contact: + md += '

Contact: ' + if not 'name' in contact: + md += '{0}'.format(contact['email']) + elif not 'email' in contact: + md += contact['name'] + else: + md += '{0} <'.format(contact['name'], contact['email']) + md += ' \n' + if 'url' in contact: + md += "

Website: {}

\n".format(contact['url']) + if 'termsOfService' in info: + md += '

Terms of Service: {}

\n'.format(info['termsOfService']) + if 'host' in json_data: + md += '

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: '{0}://{1}'.format(x, base), + json_data['schemes'] + )) + else: + md += '{0}'.format(base) + md += '

\n' + if 'description' in info: + md += '

Description: {}

\n'.format(info['description']) + md += '\n' + return md + except KeyErrori as e: + handleException('KeyError', e) + +def make_ref(ref): + href = ref.split('/')[1:] + return '{}'.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"\1", s) + reg = re.compile(r"[*_]{2}(.+?)[*_]{2}") + s = reg.sub(r"\1", s) + reg = re.compile(r"[*_](.+?)[*_]") + s = reg.sub(r"\1", s) + reg = re.compile(r"\`(.+?)\`") + s = reg.sub(r"\1", s) + return s + +def make_table(data): + md = '\n' + md += ' \n' + md += ' \n' + for col in data[0]: + md += ' \n'.format(col) + md += ' \n' + md += ' \n' + md += ' \n' + for row in data[1:]: + md += ' \n' + for cell in row: + md += ' \n'.format(cell) + md += ' \n' + md += ' \n' + md += '
{}
{}
\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 = [ "{}".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 = "True" + row.append(required) + if 'type' in fields: + type = '' + if 'type' in item: + if item['type'] == 'array': + type = "[ {} ]".format(item['items']['type']) + else: + type = item['type'] + if 'format' in item: + type += " ({})".format(item['format']) + type = "{}".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 = [ "{}".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 = '

Paths

\n' + for key in sorted(sections): + md += '

{0}

\n'.format(key) + for section in sections[key]: + md += '

{}

\n'.format( + section['href'], section['title'] + ) + operation = section['operation'] + if 'summary' in operation: + md += '

Summary: {}

\n'.format(make_html(operation['summary'])) + if 'description' in operation: + md += '

Description: {}

\n'.format(make_html(operation['description'])) + md += '
Parameters
\n' + if 'parameters' in operation and len(operation['parameters']) > 0: + md += make_params_table(operation['parameters'], json_data) + else: + md += "

None

\n" + md += '
Responses
\n' + md += make_responses_table(operation['responses']) + md += '\n' + md += '\n' + return md + +def make_contents(path_section, json_data): + md = '

Contents

\n' + md += '\n' + return md + +def make_definitions(json_data): + md = '

Models

\n' + for name in sorted(json_data['definitions']): + md += '

{0}

\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 = [ "{}".format(key) ] + if 'type' in property: + type = property['type'] + if 'format' in property: + type += " ({})".format(property['format']) + row.append("{}".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() -- cgit v1.2.3