Merge pull request #330 from matrix-org/rav/improve_examples

Improve API examples in the spec
pull/977/head
Richard van der Hoff 8 years ago
commit 0cdc2da5bf

@ -44,22 +44,25 @@ Example request:
{{endpoint.example.req | indent_block(2)}} {{endpoint.example.req | indent_block(2)}}
{% if endpoint.example.responses|length > 0 -%} {% if endpoint.responses|length > 0 -%}
Response{{"s" if endpoint.example.responses|length > 1 else "" }}: Response{{"s" if endpoint.responses|length > 1 else "" }}:
{% endif -%} {% endif -%}
{% for res in endpoint.example.responses -%} {% for res in endpoint.responses -%}
**Status code {{res["code"]}}:** **Status code {{res["code"]}}:**
{{res["description"]}} {{res["description"]}}
{% if res["example"] -%}
Example Example
.. code:: json .. code:: json
{{res["example"] | indent_block(2)}} {{res["example"] | indent_block(2)}}
{% endfor %} {% endif -%}
{% endfor %}

@ -99,10 +99,11 @@ def get_json_schema_object_fields(obj, enforce_title=False,
obj["title"] = 'NO_TITLE' obj["title"] = 'NO_TITLE'
additionalProps = obj.get("additionalProperties") additionalProps = obj.get("additionalProperties")
if additionalProps: props = obj.get("properties")
if additionalProps and not props:
# not "really" an object, just a KV store
additionalProps = inherit_parents(additionalProps) additionalProps = inherit_parents(additionalProps)
# not "really" an object, just a KV store
logger.debug("%s is a pseudo-object", obj.get("title")) logger.debug("%s is a pseudo-object", obj.get("title"))
key_type = additionalProps.get("x-pattern", "string") key_type = additionalProps.get("x-pattern", "string")
@ -127,7 +128,6 @@ def get_json_schema_object_fields(obj, enforce_title=False,
logger.debug("%s done: returning %s", obj.get("title"), tables) logger.debug("%s done: returning %s", obj.get("title"), tables)
return tables return tables
props = obj.get("properties")
if not props: if not props:
props = obj.get("patternProperties") props = obj.get("patternProperties")
if props: if props:
@ -273,9 +273,34 @@ def get_tables_for_schema(schema, mark_required=True):
return filtered return filtered
def get_example_for_schema(schema):
"""Returns a python object representing a suitable example for this object"""
if 'example' in schema:
example = schema['example']
return example
if 'properties' in schema:
res = {}
for prop_name, prop in schema['properties'].iteritems():
logger.debug("Parsing property %r" % prop_name)
prop_example = get_example_for_schema(prop)
res[prop_name] = prop_example
return res
if 'items' in schema:
return [get_example_for_schema(schema['items'])]
return schema.get('type', '??')
def get_example_for_param(param):
if 'x-example' in param:
return param['x-example']
schema = param.get('schema')
if not schema:
return None
if 'example' in schema:
return schema['example']
return json.dumps(get_example_for_schema(param['schema']),
indent=2)
class MatrixUnits(Units): class MatrixUnits(Units):
def _load_swagger_meta(self, api, group_name): def _load_swagger_meta(self, api, group_name):
endpoints = [] endpoints = []
for path in api["paths"]: for path in api["paths"]:
@ -293,10 +318,9 @@ class MatrixUnits(Units):
"req_param_by_loc": {}, "req_param_by_loc": {},
"req_body_tables": [], "req_body_tables": [],
"res_tables": [], "res_tables": [],
"responses": [],
"example": { "example": {
"req": "", "req": "",
"responses": [],
"good_response": ""
} }
} }
self.log(" ------- Endpoint: %s %s ------- " % (method, path)) self.log(" ------- Endpoint: %s %s ------- " % (method, path))
@ -330,60 +354,55 @@ class MatrixUnits(Units):
# endfor[param] # endfor[param]
good_response = None good_response = None
for code, res in single_api.get("responses", {}).items(): for code in sorted(single_api.get("responses", {}).keys()):
res = single_api["responses"][code]
if not good_response and code == 200: if not good_response and code == 200:
good_response = res good_response = res
description = res.get("description", "") description = res.get("description", "")
example = res.get("examples", {}).get("application/json", "") example = res.get("examples", {}).get("application/json", "")
if description and example: endpoint["responses"].append({
endpoint["example"]["responses"].append({ "code": code,
"code": code, "description": description,
"description": description, "example": example,
"example": example, })
})
path_template = api.get("basePath", "").rstrip("/") + path
qps = []
body = ""
for param in single_api.get("parameters", []):
try:
example = get_example_for_param(param)
if not example:
self.log(
"The parameter %s is missing an example." %
param["name"])
continue
# form example request if it has one. It "has one" if all params
# have either "x-example" or a "schema" with an "example".
params_missing_examples = [
p for p in single_api.get("parameters", []) if (
"x-example" not in p and
not Units.prop(p, "schema/example")
)
]
if len(params_missing_examples) == 0:
path_template = api.get("basePath", "").rstrip("/") + path
qps = []
body = ""
for param in single_api.get("parameters", []):
if param["in"] == "path": if param["in"] == "path":
path_template = path_template.replace( path_template = path_template.replace(
"{%s}" % param["name"], urllib.quote( "{%s}" % param["name"], urllib.quote(example)
param["x-example"]
)
) )
elif param["in"] == "body": elif param["in"] == "body":
body = param["schema"]["example"] body = example
elif param["in"] == "query": elif param["in"] == "query":
example = param["x-example"]
if type(example) == list: if type(example) == list:
for value in example: for value in example:
qps.append((param["name"], value)) qps.append((param["name"], value))
else: else:
qps.append((param["name"], example)) qps.append((param["name"], example))
query_string = "" if len(qps) == 0 else "?"+urllib.urlencode(qps) except Exception, e:
if body: raise Exception("Error handling parameter %s" % param["name"],
endpoint["example"]["req"] = "%s %s%s HTTP/1.1\nContent-Type: application/json\n\n%s" % ( e)
method.upper(), path_template, query_string, body
) query_string = "" if len(qps) == 0 else "?"+urllib.urlencode(qps)
else: if body:
endpoint["example"]["req"] = "%s %s%s HTTP/1.1\n\n" % ( endpoint["example"]["req"] = "%s %s%s HTTP/1.1\nContent-Type: application/json\n\n%s" % (
method.upper(), path_template, query_string method.upper(), path_template, query_string, body
) )
else: else:
self.log( endpoint["example"]["req"] = "%s %s%s HTTP/1.1\n\n" % (
"The following parameters are missing examples :( \n %s" % method.upper(), path_template, query_string
[ p["name"] for p in params_missing_examples ]
) )
# add response params if this API has any. # add response params if this API has any.
@ -465,9 +484,9 @@ class MatrixUnits(Units):
try: try:
req_body_tables = get_tables_for_schema(param["schema"]) req_body_tables = get_tables_for_schema(param["schema"])
except Exception, e: except Exception, e:
logger.warning("Error decoding body of API endpoint %s %s: %s", logger.warning("Error decoding body of API endpoint %s %s" %
endpoint_data["method"], endpoint_data["path"], (endpoint_data["method"], endpoint_data["path"]),
e.args[0]) exc_info=1)
return return
# put the top-level parameters into 'req_param_by_loc', and the others # put the top-level parameters into 'req_param_by_loc', and the others

Loading…
Cancel
Save