Repository: cloudtools/troposphere

Issue:
ApiGateway Model Schema should be a Dict not a string
troposphere.apigateway.Model class contains a property called schema, it is defined as 'basestring', this property should be a dict.

Ideally, you should supply a class to represent 'Schema'


Discussion:
The documentation for the CloudFormation Schema property is type "JSON object". As such you should be able to create the basestring using json.dumps(your_dict). Give that a try as a work around for now. Looking at it I could allow both a basestring and dict with the dict doing the json.dumps() in the validator. I'll leave this issue open for now to remind me to try that out.
Hi
Thanks, This worked, it temporary solved the problem, but I think it is like a hack not a permanent solution.

It is better to make it a dict instead of basestring, or to make a class to model the Schema element

Thanks a lot

Resolving patch:
diff --git a/troposphere/apigateway.py b/troposphere/apigateway.py
--- a/troposphere/apigateway.py
+++ b/troposphere/apigateway.py
@@ -1,5 +1,6 @@
-from . import AWSObject, AWSProperty
+from . import AWSHelperFn, AWSObject, AWSProperty
 from .validators import positive_integer
+import json
 
 
 def validate_authorizer_ttl(ttl_value):
@@ -183,9 +184,23 @@ class Model(AWSObject):
         "Description": (basestring, False),
         "Name": (basestring, False),
         "RestApiId": (basestring, True),
-        "Schema": (basestring, False)
+        "Schema": ((basestring, dict), False)
     }
 
+    def validate(self):
+        if 'Schema' in self.properties:
+            schema = self.properties.get('Schema')
+            if isinstance(schema, basestring):
+                # Verify it is a valid json string
+                json.loads(schema)
+            elif isinstance(schema, dict):
+                # Convert the dict to a basestring
+                self.properties['Schema'] = json.dumps(schema)
+            elif isinstance(schema, AWSHelperFn):
+                pass
+            else:
+                raise ValueError("Schema must be a str or dict")
+
 
 class Resource(AWSObject):
     resource_type = "AWS::ApiGateway::Resource"


Test patch:
diff --git a/tests/test_apigateway.py b/tests/test_apigateway.py
new file mode 100644
--- /dev/null
+++ b/tests/test_apigateway.py
@@ -0,0 +1,60 @@
+import unittest
+from troposphere import Join
+from troposphere.apigateway import Model
+
+
+class TestModel(unittest.TestCase):
+    def test_schema(self):
+        # Check with no schema
+        model = Model(
+            "schema",
+            RestApiId="apiid",
+        )
+        model.validate()
+
+        # Check valid json schema string
+        model = Model(
+            "schema",
+            RestApiId="apiid",
+            Schema='{"a": "b"}',
+        )
+        model.validate()
+
+        # Check invalid json schema string
+        model = Model(
+            "schema",
+            RestApiId="apiid",
+            Schema='{"a: "b"}',
+        )
+        with self.assertRaises(ValueError):
+            model.validate()
+
+        # Check accepting dict and converting to string in validate
+        d = {"c": "d"}
+        model = Model(
+            "schema",
+            RestApiId="apiid",
+            Schema=d
+        )
+        model.validate()
+        self.assertEqual(model.properties['Schema'], '{"c": "d"}')
+
+        # Check invalid Schema type
+        with self.assertRaises(TypeError):
+            model = Model(
+                "schema",
+                RestApiId="apiid",
+                Schema=1
+            )
+
+        # Check Schema being an AWSHelperFn
+        model = Model(
+            "schema",
+            RestApiId="apiid",
+            Schema=Join(':', ['{"a', ': "b"}']),
+        )
+        model.validate()
+
+
+if __name__ == '__main__':
+    unittest.main()