Skip to content

Commit

Permalink
Objects and Arrays recusively construct examples from examples of the…
Browse files Browse the repository at this point in the history
…ir children
  • Loading branch information
mjp4 committed Feb 5, 2020
1 parent 3fecd3e commit ba1da6e
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 1 deletion.
24 changes: 24 additions & 0 deletions connexion/operations/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def example_response(self, status_code=None, content_type=None):
schema_example_path = [
str(status_code), 'content', content_type, 'schema', 'example'
]
schema_path = [str(status_code), 'content', content_type, 'schema']

try:
status_code = int(status_code)
Expand All @@ -202,9 +203,32 @@ def example_response(self, status_code=None, content_type=None):
try:
return (deep_get(self._responses, schema_example_path),
status_code)
except KeyError:
pass

try:
return (self._nested_example(deep_get(self._responses, schema_path)),
status_code)
except KeyError:
return (None, status_code)

def _nested_example(self, schema):
try:
return schema["example"]
except KeyError:
pass
try:
# Recurse if schema is an object
return {key: self._nested_example(value)
for (key, value) in schema["properties"].items()}
except KeyError:
pass
try:
# Recurse if schema is an array
return [self._nested_example(schema["items"])]
except KeyError:
raise

def get_path_parameter_types(self):
types = {}
path_parameters = (p for p in self.parameters if p["in"] == "path")
Expand Down
25 changes: 25 additions & 0 deletions connexion/operations/swagger2.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ def example_response(self, status_code=None, *args, **kwargs):
status_code = status_code or sorted(self._responses.keys())[0]
examples_path = [str(status_code), 'examples']
schema_example_path = [str(status_code), 'schema', 'example']
schema_path = [str(status_code), 'schema']

try:
status_code = int(status_code)
except ValueError:
Expand All @@ -194,9 +196,32 @@ def example_response(self, status_code=None, *args, **kwargs):
try:
return (deep_get(self._responses, schema_example_path),
status_code)
except KeyError:
pass

try:
return (self._nested_example(deep_get(self._responses, schema_path)),
status_code)
except KeyError:
return (None, status_code)

def _nested_example(self, schema):
try:
return schema["example"]
except KeyError:
pass
try:
# Recurse if schema is an object
return {key: self._nested_example(value)
for (key, value) in schema["properties"].items()}
except KeyError:
pass
try:
# Recurse if schema is an array
return [self._nested_example(schema["items"])]
except KeyError:
raise

@property
def body_schema(self):
"""
Expand Down
144 changes: 143 additions & 1 deletion tests/test_mock.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from connexion.mock import MockResolver
from connexion.operations import Swagger2Operation
from connexion.operations import Swagger2Operation, OpenAPIOperation


def test_mock_resolver_default():
Expand Down Expand Up @@ -107,6 +107,148 @@ def test_mock_resolver_example():
assert status_code == 200
assert response == {'foo': 'bar'}

def test_mock_resolver_example_nested_in_object():
resolver = MockResolver(mock_all=True)

responses = {
'default': {
'schema': {
'type': 'object',
'properties': {
'foo': {
'type': 'string',
'example': 'bar'
}
},
}
}
}

operation = Swagger2Operation(api=None,
method='GET',
path='endpoint',
path_parameters=[],
operation={
'responses': responses
},
app_produces=['application/json'],
app_consumes=['application/json'],
app_security=[],
security_definitions={},
definitions={},
parameter_definitions={},
resolver=resolver)
assert operation.operation_id == 'mock-1'

response, status_code = resolver.mock_operation(operation)
assert status_code == 200
assert response == {'foo': 'bar'}

def test_mock_resolver_example_nested_in_list():
resolver = MockResolver(mock_all=True)

responses = {
'default': {
'schema': {
'type': 'array',
'items': {
'type': 'string',
'example': 'bar'
},
}
}
}

operation = Swagger2Operation(api=None,
method='GET',
path='endpoint',
path_parameters=[],
operation={
'responses': responses
},
app_produces=['application/json'],
app_consumes=['application/json'],
app_security=[],
security_definitions={},
definitions={},
parameter_definitions={},
resolver=resolver)
assert operation.operation_id == 'mock-1'

response, status_code = resolver.mock_operation(operation)
assert status_code == 200
assert response == ['bar']

def test_mock_resolver_example_nested_in_object_openapi():
resolver = MockResolver(mock_all=True)

responses = {
'default': {
'content': {
'application/json': {
'schema': {
'type': 'object',
'properties': {
'foo': {
'type': 'string',
'example': 'bar'
}
}
}
}
}
}
}

operation = OpenAPIOperation(api=None,
method='GET',
path='endpoint',
path_parameters=[],
operation={
'responses': responses
},
app_security=[],
resolver=resolver)
assert operation.operation_id == 'mock-1'

response, status_code = resolver.mock_operation(operation)
assert status_code == 200
assert response == {'foo': 'bar'}

def test_mock_resolver_example_nested_in_list_openapi():
resolver = MockResolver(mock_all=True)

responses = {
'default': {
'content': {
'application/json': {
'schema': {
'type': 'array',
'items': {
'type': 'string',
'example': 'bar'
}
}
}
}
}
}

operation = OpenAPIOperation(api=None,
method='GET',
path='endpoint',
path_parameters=[],
operation={
'responses': responses
},
app_security=[],
resolver=resolver)
assert operation.operation_id == 'mock-1'

response, status_code = resolver.mock_operation(operation)
assert status_code == 200
assert response == ['bar']

def test_mock_resolver_no_examples():
resolver = MockResolver(mock_all=True)

Expand Down

0 comments on commit ba1da6e

Please sign in to comment.