aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorSun Howwrongbum <sun@adrenosapient.com>2016-12-13 16:43:31 +0530
committerSun Howwrongbum <sun@adrenosapient.com>2016-12-13 16:43:31 +0530
commita04c318ef92623478cf07b2f9ffca90b0f6507ad (patch)
tree3eadd95628360c4900803ba24ef5c3e733535320 /tools
parent9d707dac529b922f491da45b73121e5e2ca96773 (diff)
downloadtraccar-server-a04c318ef92623478cf07b2f9ffca90b0f6507ad.tar.gz
traccar-server-a04c318ef92623478cf07b2f9ffca90b0f6507ad.tar.bz2
traccar-server-a04c318ef92623478cf07b2f9ffca90b0f6507ad.zip
Add script to generate HTML from swagger.json
- #2680
Diffstat (limited to 'tools')
-rwxr-xr-xtools/swagger2html.py354
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} &lt;<a href="mailto:{1}"&gt;{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()