Repository: sdementen/oasapi

Issue:
integer status codes trigger exception in validation
the jsonschema validator expects all keys of the swagger to be strings.
if a swagger is given in yaml format with integer values for response codes, the jsonschema will crash

Discussion:

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 795c61f..262f728 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -3,6 +3,11 @@ Changelog
 =========
 
 
+dev
+---
+
+* fix integer response code raising exception (closes #14)
+
 0.1.16   (2020-02-08)
 ---------------------
 
diff --git a/src/oasapi/jspaths.py b/src/oasapi/jspaths.py
new file mode 100644
index 0000000..cdcf67e
--- /dev/null
+++ b/src/oasapi/jspaths.py
@@ -0,0 +1,25 @@
+from jsonpath_ng import parse, Union, Child
+
+from oasapi.common import OPERATIONS_LOWER, REFERENCE_SECTIONS
+
+# list of JSPATH for different structures
+
+JSPATH_INFO = parse(f"info")
+JSPATH_ENDPOINTS = parse(f"paths.*")
+JSPATH_OPERATIONS = Child(JSPATH_ENDPOINTS, parse(f"({'|'.join(OPERATIONS_LOWER)})"))
+JSPATH_OPERATION_RESPONSES = Child(JSPATH_OPERATIONS, parse("responses"))
+JSPATH_OPERATIONID = Child(JSPATH_OPERATIONS, parse("operationId"))
+JSPATH_OPERATION_TAGS = Child(JSPATH_OPERATIONS, parse(f"tags"))
+JSPATH_SECURITY_OPERATION = Child(JSPATH_OPERATIONS, parse("security.[*].*"))
+JSPATH_SECURITY_GLOBAL = parse("security.[*].*")
+JSPATH_SECURITY = Union(JSPATH_SECURITY_GLOBAL, JSPATH_SECURITY_OPERATION)
+JSPATH_PARAMETERS_GLOBAL = parse("parameters.[*]")
+JSPATH_PARAMETERS_PATH = parse(f"paths.*.parameters.[*]")
+JSPATH_PARAMETERS_OPERATION = Child(JSPATH_OPERATIONS, parse("parameters.[*]"))
+JSPATH_PARAMETERS = Union(
+    JSPATH_PARAMETERS_GLOBAL, Union(JSPATH_PARAMETERS_PATH, JSPATH_PARAMETERS_OPERATION)
+)
+JSPATH_PATHS_REFERENCES = parse("paths..'$ref'")
+JSPATH_REFERENCES = parse("$..'$ref'")
+JSPATH_COMPONENTS = parse(f"$.({'|'.join(REFERENCE_SECTIONS)}).*")
+JSPATH_TAGS = parse("tags.[*].name")
diff --git a/src/oasapi/validation.py b/src/oasapi/validation.py
index 51afa73..896c748 100644
--- a/src/oasapi/validation.py
+++ b/src/oasapi/validation.py
@@ -11,13 +11,13 @@ from typing import Set, Dict, Tuple, List
 
 from jsonschema import Draft4Validator
 
-from oasapi.common import (
-    get_elements,
-    REFERENCE_SECTIONS,
+from oasapi.common import get_elements, REFERENCE_SECTIONS
+from oasapi.jspaths import (
     JSPATH_SECURITY,
     JSPATH_PARAMETERS,
     JSPATH_REFERENCES,
     JSPATH_OPERATIONID,
+    JSPATH_OPERATION_RESPONSES,
 )
 from .events import (
     ReferenceNotFoundValidationError,
@@ -308,6 +308,12 @@ def check_schema(swagger: Dict) -> Set[ValidationError]:
     schema = json.load((Path(__file__).parent / "schemas" / "schema_swagger.json").open())
     v = Draft4Validator(schema)
 
+    # convert any key to string (as json swagger expects all keys to be str and response code are sometimes integer)
+    for name, value, path in get_elements(swagger, JSPATH_OPERATION_RESPONSES):
+        for k in list(value.keys()):
+            if isinstance(k, int):
+                value[str(k)] = value.pop(k)
+
     return {
         JsonSchemaValidationError(path=tuple(error.absolute_path), reason=error.message)
         for error in v.iter_errors(swagger)


Test patch:
diff --git a/tests/test_validation.py b/tests/test_validation.py
index c9232f9..873f9fa 100644
--- a/tests/test_validation.py
+++ b/tests/test_validation.py
@@ -130,6 +130,39 @@ paths:
     }
 
 
+def test_check_schema_integer_as_response_code():
+    swagger_str = """
+swagger: '2.0'
+info:
+  version: 1.0
+  title: my api
+paths:
+  /foo:
+    get:
+      responses:
+        200:
+          $ref: "#/definitions/some-definition"
+      security:
+      - baz: "not-a-list"
+    """
+    swagger = yaml.safe_load(swagger_str)
+    results = check_schema(swagger)
+
+    # no error in this basic test
+    assert results == {
+        JsonSchemaValidationError(
+            path=("info", "version"),
+            reason="1.0 is not of type 'string'",
+            type="Json schema validator error",
+        ),
+        JsonSchemaValidationError(
+            path=("paths", "/foo", "get", "security", 0, "baz"),
+            reason="'not-a-list' is not of type 'array'",
+            type="Json schema validator error",
+        ),
+    }
+
+
 def test_check_references():
     swagger_str = """
 swagger: '2.0'