From 63f08bace61b01d629bcdc3beaaf8870c7bfd993 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Fri, 18 Sep 2015 14:40:48 +0100 Subject: [PATCH 1/4] Fix the examples in the swagger API documentation to be valid JSON --- api/client-server/v1/presence.yaml | 6 +++--- api/client-server/v1/sync.yaml | 2 +- templating/matrix_templates/units.py | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/api/client-server/v1/presence.yaml b/api/client-server/v1/presence.yaml index 717e9c473..5684398b0 100644 --- a/api/client-server/v1/presence.yaml +++ b/api/client-server/v1/presence.yaml @@ -101,7 +101,7 @@ paths: The length of time in milliseconds since an action was performed by this user. status_msg: - type: string + type: [string, "null"] description: The state message for this user if one was set. 404: description: |- @@ -185,7 +185,7 @@ paths: "last_active_ago": 395, "presence": "offline", "user_id": "@alice:matrix.org" - } + }, "type": "m.presence" }, { @@ -195,7 +195,7 @@ paths: "last_active_ago": 16874, "presence": "online", "user_id": "@marisa:matrix.org" - } + }, "type": "m.presence" } ] diff --git a/api/client-server/v1/sync.yaml b/api/client-server/v1/sync.yaml index 27c7073c4..833c425ab 100644 --- a/api/client-server/v1/sync.yaml +++ b/api/client-server/v1/sync.yaml @@ -343,7 +343,7 @@ paths: "body": "Hello world!", "msgtype": "m.text" }, - "room_id:" "!wfgy43Sg4a:matrix.org", + "room_id:": "!wfgy43Sg4a:matrix.org", "user_id": "@bob:matrix.org", "event_id": "$asfDuShaf7Gafaw:matrix.org", "type": "m.room.message" diff --git a/templating/matrix_templates/units.py b/templating/matrix_templates/units.py index 8e803d3ba..3083a51ea 100644 --- a/templating/matrix_templates/units.py +++ b/templating/matrix_templates/units.py @@ -87,6 +87,8 @@ def get_json_schema_object_fields(obj, enforce_title=False): desc += ( " Must be '%s'." % props[key_name]["enum"][0] ) + if isinstance(value_type, list): + value_type = " or ".join(value_type) fields["rows"].append({ "key": key_name, From 299a4356d49e9b694c1fb6340cda2669e8e30377 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Fri, 18 Sep 2015 16:10:21 +0100 Subject: [PATCH 2/4] Add script to check that the example responses in the swagger matches the examples. --- api/check_examples.py | 75 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100755 api/check_examples.py diff --git a/api/check_examples.py b/api/check_examples.py new file mode 100755 index 000000000..cec8ac09c --- /dev/null +++ b/api/check_examples.py @@ -0,0 +1,75 @@ +#! /usr/bin/env python + +import sys + +def import_error(module, package, debian, error): + sys.stderr.write(( + "Error importing %(module)s: %(error)r\n" + "To install %(module)s run:\n" + " pip install %(package)s\n" + "or on Debian run:\n" + " sudo apt-get install python-%(debian)s\n" + ) % locals()) + if __name__=='__main__': + sys.exit(1) + +try: + import jsonschema +except ImportError as e: + import_error("jsonschema", "jsonschema", "jsonschema", e) + raise + +try: + import yaml +except ImportError as e: + import_error("yaml", "PyYAML", "yaml", e) + raise + +import json +import os + +def check_response(filepath, request, code, response): + try: + example = json.loads( + response.get('examples', {}).get('application/json', "null") + ) + except Exception as e: + raise ValueError("Error parsing JSON example response for %r %r" % ( + request, code + ), e) + schema = response.get('schema') + fileurl = "file://" + os.path.abspath(filepath) + if example and schema: + try: + print ("Checking schema for: %r %r %r" % (filepath, request, code)) + # Setting the 'id' tells jsonschema where the file is so that it + # can correctly resolve relative $ref references in the schema + schema['id'] = fileurl + jsonschema.validate(example, schema) + except Exception as e: + raise ValueError("Error validating JSON schema for %r %r" %( + request, code + ), e) + + +def check_swagger_file(filepath): + with open(filepath) as f: + swagger = yaml.load(f) + + for path, path_api in swagger['paths'].items(): + for method, request_api in path_api.items(): + request = "%s %s" % (method.upper(), path) + try: + responses = request_api['responses'] + except KeyError: + raise ValueError("No responses for %r" % (request,)) + for code, response in responses.items(): + check_response(filepath, request, code, response) + + +if __name__=='__main__': + for path in sys.argv[1:]: + try: + check_swagger_file(path) + except Exception as e: + raise ValueError("Error checking file %r" % (path,), e) From 9896f98e2b63fd6204482bd9c7b8ba699487576d Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Fri, 18 Sep 2015 16:21:48 +0100 Subject: [PATCH 3/4] Search for yaml swagger files if check_examples.py is run without arguments. --- api/check_examples.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/api/check_examples.py b/api/check_examples.py index cec8ac09c..9b2f1fe99 100755 --- a/api/check_examples.py +++ b/api/check_examples.py @@ -1,6 +1,9 @@ #! /usr/bin/env python import sys +import json +import os + def import_error(module, package, debian, error): sys.stderr.write(( @@ -10,7 +13,7 @@ def import_error(module, package, debian, error): "or on Debian run:\n" " sudo apt-get install python-%(debian)s\n" ) % locals()) - if __name__=='__main__': + if __name__ == '__main__': sys.exit(1) try: @@ -25,8 +28,6 @@ except ImportError as e: import_error("yaml", "PyYAML", "yaml", e) raise -import json -import os def check_response(filepath, request, code, response): try: @@ -47,7 +48,7 @@ def check_response(filepath, request, code, response): schema['id'] = fileurl jsonschema.validate(example, schema) except Exception as e: - raise ValueError("Error validating JSON schema for %r %r" %( + raise ValueError("Error validating JSON schema for %r %r" % ( request, code ), e) @@ -56,7 +57,7 @@ def check_swagger_file(filepath): with open(filepath) as f: swagger = yaml.load(f) - for path, path_api in swagger['paths'].items(): + for path, path_api in swagger.get('paths', {}).items(): for method, request_api in path_api.items(): request = "%s %s" % (method.upper(), path) try: @@ -67,8 +68,15 @@ def check_swagger_file(filepath): check_response(filepath, request, code, response) -if __name__=='__main__': - for path in sys.argv[1:]: +if __name__ == '__main__': + paths = sys.argv[1:] + if not paths: + paths = [] + for (root, dirs, files) in os.walk(os.curdir): + for filename in files: + if filename.endswith(".yaml"): + paths.append(os.path.join(root, filename)) + for path in paths: try: check_swagger_file(path) except Exception as e: From f827765ba1999073bc9357695b27bcc3e7e0c30c Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Fri, 18 Sep 2015 16:35:27 +0100 Subject: [PATCH 4/4] Make to code to skip checking swagger responses which don't have an application/json example clearer. --- api/check_examples.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/api/check_examples.py b/api/check_examples.py index 9b2f1fe99..00e75263c 100755 --- a/api/check_examples.py +++ b/api/check_examples.py @@ -30,10 +30,11 @@ except ImportError as e: def check_response(filepath, request, code, response): + example = None try: - example = json.loads( - response.get('examples', {}).get('application/json', "null") - ) + example_json = response.get('examples', {}).get('application/json') + if example_json: + example = json.loads(example_json) except Exception as e: raise ValueError("Error parsing JSON example response for %r %r" % ( request, code