Skip to content

Commit 97724ae

Browse files
author
Kirill Matyunin
committed
fixing core-api#37 issue support of definitions for nested objects
1 parent 63ca501 commit 97724ae

File tree

3 files changed

+153
-7
lines changed

3 files changed

+153
-7
lines changed

openapi_codec/encode.py

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import coreschema
22
from collections import OrderedDict
3+
from coreapi.document import Field
34
from coreapi.compat import urlparse
45
from openapi_codec.utils import get_method, get_encoding, get_location, get_links_from_document
56

@@ -23,15 +24,61 @@ def generate_swagger_object(document):
2324
swagger['schemes'] = [parsed_url.scheme]
2425

2526
swagger['paths'] = _get_paths_object(document)
27+
swagger['definitions'] = _get_definitions(document)
2628

2729
return swagger
2830

2931

32+
def _get_definitions(document):
33+
34+
definitions = dict()
35+
links = _get_links(document)
36+
37+
def get_field_def_data(field_item, defs):
38+
39+
definition_data = {
40+
'type': 'object',
41+
'properties': {}
42+
}
43+
44+
if isinstance(field_item, coreschema.Object):
45+
props = field_item.properties
46+
else:
47+
props = field_item.schema.properties
48+
49+
for f_name, f_schema in props.iteritems():
50+
51+
if _get_field_type(f_schema) is 'object':
52+
defs[f_name] = get_field_def_data(f_schema, defs)
53+
definition_data['properties'][f_name] = {
54+
'$ref': '#/definitions/{}'.format(f_name)
55+
}
56+
else:
57+
definition_data['properties'][f_name] = {
58+
'type': _get_field_type(f_schema),
59+
'description': ''
60+
}
61+
62+
return definition_data
63+
64+
for _, link, _ in links:
65+
for field in link.fields:
66+
field_type = _get_field_type(field)
67+
if field_type == 'object':
68+
definitions[field.name] = get_field_def_data(field, definitions)
69+
70+
if field_type == 'array':
71+
item_name = '{}_item'.format(field.name)
72+
definitions[item_name] = get_field_def_data(field.schema.items, definitions)
73+
74+
return definitions
75+
76+
3077
def _add_tag_prefix(item):
3178
operation_id, link, tags = item
3279
if tags:
3380
operation_id = tags[0] + '_' + operation_id
34-
return (operation_id, link, tags)
81+
return operation_id, link, tags
3582

3683

3784
def _get_links(document):
@@ -114,8 +161,10 @@ def _get_field_type(field):
114161
# Deprecated
115162
return field.type
116163

117-
if field.schema is None:
118-
return 'string'
164+
if isinstance(field, Field):
165+
cls = field.schema.__class__
166+
else:
167+
cls = field.__class__
119168

120169
return {
121170
coreschema.String: 'string',
@@ -124,7 +173,7 @@ def _get_field_type(field):
124173
coreschema.Boolean: 'boolean',
125174
coreschema.Array: 'array',
126175
coreschema.Object: 'object',
127-
}.get(field.schema.__class__, 'string')
176+
}.get(cls, 'string')
128177

129178

130179
def _get_parameters(link, encoding):
@@ -160,8 +209,14 @@ def _get_parameters(link, encoding):
160209
'description': field_description,
161210
'type': field_type,
162211
}
212+
163213
if field_type == 'array':
164-
schema_property['items'] = {'type': 'string'}
214+
item_name = '{}_item'.format(field.name)
215+
schema_property['items'] = {'$ref': '#/definitions/{}'.format(item_name)}
216+
217+
if field_type == 'object':
218+
schema_property = {'$ref': '#/definitions/{}'.format(field.name)}
219+
165220
properties[field.name] = schema_property
166221
if field.required:
167222
required.append(field.name)

tests/test_encode.py

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import coreapi
22
import coreschema
3-
from openapi_codec.encode import generate_swagger_object, _get_parameters
3+
4+
from collections import OrderedDict
5+
from openapi_codec.encode import generate_swagger_object, _get_parameters, _get_definitions
46
from unittest import TestCase
57

68

@@ -32,6 +34,11 @@ def test_schemes(self):
3234
expected = ['https']
3335
self.assertEquals(self.swagger['schemes'], expected)
3436

37+
def test_definitions(self):
38+
self.assertIn('definitions', self.swagger)
39+
expected = dict()
40+
self.assertEquals(self.swagger['definitions'], expected)
41+
3542

3643
class TestPaths(TestCase):
3744
def setUp(self):
@@ -101,3 +108,88 @@ def test_expected_fields(self):
101108
'type': 'string' # Everything is a string for now.
102109
}
103110
self.assertEquals(self.swagger[0], expected)
111+
112+
113+
class TestDefinitions(TestCase):
114+
115+
def setUp(self):
116+
117+
obj_props = OrderedDict()
118+
obj_props['foo'] = coreschema.String()
119+
obj_props['bar'] = coreschema.Integer()
120+
121+
self.object_field = coreapi.Field(
122+
name='dummy_object',
123+
required=True,
124+
location='form',
125+
schema=coreschema.Object(
126+
properties=obj_props
127+
)
128+
)
129+
130+
self.array_field = coreapi.Field(
131+
name='dummy_array',
132+
location='form',
133+
schema=coreschema.Array(
134+
items=self.object_field
135+
)
136+
)
137+
138+
self.link = coreapi.Link(
139+
action='post',
140+
url='/users/',
141+
fields=[self.object_field, self.array_field]
142+
)
143+
144+
self.document = coreapi.Document(
145+
content={
146+
'users': {
147+
'create': self.link,
148+
}
149+
}
150+
)
151+
152+
self.definitions = _get_definitions(self.document)
153+
self.parameters = _get_parameters(self.link, '')
154+
self.swagger = generate_swagger_object(self.document)
155+
156+
def test_basic_definitions(self):
157+
158+
print self.definitions
159+
160+
self.assertIn('definitions', self.swagger)
161+
self.assertIn('dummy_object', self.definitions)
162+
self.assertIn('dummy_array_item', self.definitions)
163+
164+
expected_dummy_object_def = {
165+
'type': 'object',
166+
'properties': {
167+
'foo': {'type': 'string', 'description': ''},
168+
'bar': {'type': 'integer', 'description': ''}
169+
}
170+
}
171+
172+
self.assertEqual(self.definitions.get('dummy_object'), expected_dummy_object_def)
173+
self.assertEqual(self.definitions.get('dummy_array_item'), expected_dummy_object_def)
174+
175+
expected_dummy_parameters = [{
176+
'schema': {
177+
'required': ['dummy_object'],
178+
'type': 'object',
179+
'properties': {
180+
'dummy_array': {
181+
'items': {
182+
'$ref': '#/definitions/dummy_array_item'
183+
},
184+
'type': 'array',
185+
'description': ''
186+
},
187+
'dummy_object': {
188+
'$ref': '#/definitions/dummy_object'
189+
}
190+
}
191+
},
192+
'name': 'data',
193+
'in': 'body'
194+
}]
195+
self.assertEqual(self.parameters, expected_dummy_parameters)

tests/test_mappings.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,6 @@ def test_mapping():
202202
coreapi.Field(
203203
name='example',
204204
location='body',
205-
206205
schema=coreschema.String()
207206
)
208207
]

0 commit comments

Comments
 (0)