stoobly-agent 0.34.7__py3-none-any.whl → 0.34.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- stoobly_agent/__init__.py +1 -1
- stoobly_agent/app/api/requests_controller.py +1 -1
- stoobly_agent/app/cli/helpers/endpoints_import_service.py +70 -11
- stoobly_agent/app/cli/helpers/openapi_endpoint_adapter.py +108 -207
- stoobly_agent/app/cli/helpers/schema_builder.py +11 -88
- stoobly_agent/app/proxy/replay/body_parser_service.py +1 -1
- stoobly_agent/app/proxy/run.py +0 -1
- stoobly_agent/app/proxy/utils/allowed_request_service.py +10 -0
- stoobly_agent/cli.py +11 -2
- stoobly_agent/test/app/cli/helpers/openapi_endpoint_adapter_missing_info_test.py +25 -15
- stoobly_agent/test/app/cli/helpers/openapi_endpoint_adapter_missing_oauth2_scopes_test.py +26 -16
- stoobly_agent/test/app/cli/helpers/openapi_endpoint_adapter_missing_servers_test.py +25 -15
- stoobly_agent/test/app/cli/helpers/openapi_endpoint_adapter_test.py +79 -9
- stoobly_agent/test/app/cli/helpers/schema_builder_test.py +22 -7
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
- stoobly_agent/test/app/proxy/replay/body_parser_service_test.py +3 -3
- {stoobly_agent-0.34.7.dist-info → stoobly_agent-0.34.9.dist-info}/METADATA +1 -1
- {stoobly_agent-0.34.7.dist-info → stoobly_agent-0.34.9.dist-info}/RECORD +21 -21
- {stoobly_agent-0.34.7.dist-info → stoobly_agent-0.34.9.dist-info}/LICENSE +0 -0
- {stoobly_agent-0.34.7.dist-info → stoobly_agent-0.34.9.dist-info}/WHEEL +0 -0
- {stoobly_agent-0.34.7.dist-info → stoobly_agent-0.34.9.dist-info}/entry_points.txt +0 -0
stoobly_agent/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
COMMAND = 'stoobly-agent'
|
2
|
-
VERSION = '0.34.
|
2
|
+
VERSION = '0.34.9'
|
@@ -41,7 +41,7 @@ class RequestsController:
|
|
41
41
|
return
|
42
42
|
|
43
43
|
raw_requests = body_params.get('requests')
|
44
|
-
payloads_delimitter = body_params.get('payloads_delimitter') or REQUEST_DELIMITTER
|
44
|
+
payloads_delimitter = body_params.get('payloads_delimitter') or REQUEST_DELIMITTER
|
45
45
|
toks = raw_requests.split(payloads_delimitter)
|
46
46
|
|
47
47
|
if len(toks) % 2 != 0:
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import json
|
2
2
|
import requests
|
3
3
|
import sys
|
4
|
-
from typing import Dict
|
4
|
+
from typing import Dict, TypedDict, Optional
|
5
5
|
|
6
6
|
from .endpoints_import_context import EndpointsImportContext
|
7
7
|
from stoobly_agent.app.models.types import ENDPOINT_COMPONENT_NAMES
|
@@ -16,12 +16,19 @@ from stoobly_agent.lib.api.response_header_names_resource import ResponseHeaderN
|
|
16
16
|
from stoobly_agent.lib.api.response_param_names_resource import ResponseParamNamesResource
|
17
17
|
from stoobly_agent.lib.logger import bcolors
|
18
18
|
|
19
|
+
class ComponentImportArgs(TypedDict):
|
20
|
+
project_id: int
|
21
|
+
endpoint_id: int
|
22
|
+
resource: EndpointsResource
|
23
|
+
component: RequestComponentName
|
24
|
+
parents: Optional[Dict]
|
25
|
+
|
19
26
|
def import_endpoints(context: EndpointsImportContext):
|
20
27
|
for endpoint in context.endpoints:
|
21
28
|
for endpoint_handler in context.endpoint_handlers:
|
22
29
|
endpoint_handler(endpoint)
|
23
30
|
|
24
|
-
try:
|
31
|
+
try:
|
25
32
|
res = import_endpoint(context.project_id, context.resources['endpoint'], endpoint)
|
26
33
|
except requests.HTTPError as e:
|
27
34
|
error_handler(e, f"Failed to import endpoint: {endpoint['method']} {endpoint['path']}")
|
@@ -57,7 +64,12 @@ def import_endpoint(project_id: int, endpoint_resource: EndpointsResource, endpo
|
|
57
64
|
|
58
65
|
res.raise_for_status()
|
59
66
|
|
60
|
-
def import_header_name(
|
67
|
+
def import_header_name(args: ComponentImportArgs):
|
68
|
+
project_id = args['project_id']
|
69
|
+
endpoint_id = args['endpoint_id']
|
70
|
+
header_name_resource = args['resource']
|
71
|
+
header_name = args['component']
|
72
|
+
|
61
73
|
res: requests.Response = header_name_resource.create(endpoint_id, {
|
62
74
|
'name': header_name.get('name'),
|
63
75
|
'is_deterministic': header_name.get('is_deterministic', True),
|
@@ -68,7 +80,18 @@ def import_header_name(project_id: int, endpoint_id: int, header_name_resource:
|
|
68
80
|
|
69
81
|
res.raise_for_status()
|
70
82
|
|
71
|
-
def import_body_param_name(
|
83
|
+
def import_body_param_name(args: ComponentImportArgs):
|
84
|
+
project_id = args['project_id']
|
85
|
+
endpoint_id = args['endpoint_id']
|
86
|
+
body_param_name_resource = args['resource']
|
87
|
+
body_param_name = args['component']
|
88
|
+
parents = args['parents']
|
89
|
+
|
90
|
+
body_param_name_id = None
|
91
|
+
parent_id = body_param_name.get('body_param_name_id')
|
92
|
+
if parent_id:
|
93
|
+
body_param_name_id = parents[parent_id]
|
94
|
+
|
72
95
|
res: requests.Response = body_param_name_resource.create(endpoint_id, {
|
73
96
|
'name': body_param_name.get('name'),
|
74
97
|
'is_deterministic': body_param_name.get('is_deterministic', True),
|
@@ -77,11 +100,20 @@ def import_body_param_name(project_id: int, endpoint_id: int, body_param_name_re
|
|
77
100
|
'query': body_param_name.get('query'),
|
78
101
|
'endpoint_id': endpoint_id,
|
79
102
|
'project_id': project_id,
|
103
|
+
'body_param_name_id': body_param_name_id
|
80
104
|
})
|
81
105
|
|
82
106
|
res.raise_for_status()
|
83
107
|
|
84
|
-
|
108
|
+
res_id = res.json()['id']
|
109
|
+
parents[body_param_name['id']] = res_id
|
110
|
+
|
111
|
+
def import_query_param_name(args: ComponentImportArgs):
|
112
|
+
project_id = args['project_id']
|
113
|
+
endpoint_id = args['endpoint_id']
|
114
|
+
query_param_name_resource = args['resource']
|
115
|
+
query_param_name = args['component']
|
116
|
+
|
85
117
|
res: requests.Response = query_param_name_resource.create(endpoint_id, {
|
86
118
|
'name': query_param_name.get('name'),
|
87
119
|
'is_deterministic': query_param_name.get('is_deterministic', True),
|
@@ -92,7 +124,18 @@ def import_query_param_name(project_id: int, endpoint_id: int, query_param_name_
|
|
92
124
|
|
93
125
|
res.raise_for_status()
|
94
126
|
|
95
|
-
def import_response_param_name(
|
127
|
+
def import_response_param_name(args: ComponentImportArgs):
|
128
|
+
project_id = args['project_id']
|
129
|
+
endpoint_id = args['endpoint_id']
|
130
|
+
response_param_name_resource = args['resource']
|
131
|
+
response_param_name = args['component']
|
132
|
+
parents = args['parents']
|
133
|
+
|
134
|
+
response_param_name_id = None
|
135
|
+
parent_id = response_param_name.get('response_param_name_id')
|
136
|
+
if parent_id:
|
137
|
+
response_param_name_id = parents[parent_id]
|
138
|
+
|
96
139
|
res: requests.Response = response_param_name_resource.create(endpoint_id, {
|
97
140
|
'name': response_param_name.get('name'),
|
98
141
|
'is_deterministic': response_param_name.get('is_deterministic', True),
|
@@ -101,11 +144,21 @@ def import_response_param_name(project_id: int, endpoint_id: int, response_param
|
|
101
144
|
'query': response_param_name.get('query'),
|
102
145
|
'endpoint_id': endpoint_id,
|
103
146
|
'project_id': project_id,
|
147
|
+
'response_param_name_id': response_param_name_id
|
104
148
|
})
|
105
149
|
|
106
150
|
res.raise_for_status()
|
107
151
|
|
108
|
-
|
152
|
+
res_id = res.json()['id']
|
153
|
+
parents[response_param_name['id']] = res_id
|
154
|
+
|
155
|
+
|
156
|
+
def import_response_header_name(args: ComponentImportArgs):
|
157
|
+
project_id = args['project_id']
|
158
|
+
endpoint_id = args['endpoint_id']
|
159
|
+
response_header_name_resource = args['resource']
|
160
|
+
response_header_name = args['component']
|
161
|
+
|
109
162
|
res: requests.Response = response_header_name_resource.create(endpoint_id, {
|
110
163
|
'name': response_header_name.get('name'),
|
111
164
|
'is_deterministic': response_header_name.get('is_deterministic', True),
|
@@ -124,14 +177,20 @@ component_name_import_dispatch = {
|
|
124
177
|
ENDPOINT_COMPONENT_NAMES[4]: import_response_param_name
|
125
178
|
}
|
126
179
|
|
127
|
-
def process_import(component_name: str, *args):
|
128
|
-
return component_name_import_dispatch[component_name](*args)
|
129
|
-
|
130
180
|
def import_component_names(project_id: int, endpoint_id: int, endpoint: EndpointShowResponse, resources: Dict[str, EndpointsResource]):
|
131
181
|
for component_name in ENDPOINT_COMPONENT_NAMES:
|
182
|
+
parents: Dict[int, int] = {}
|
132
183
|
for component in endpoint.get(f'{component_name}s', {}):
|
133
184
|
resource = resources[component_name]
|
134
|
-
|
185
|
+
args = {
|
186
|
+
'project_id': project_id,
|
187
|
+
'endpoint_id': endpoint_id,
|
188
|
+
'resource': resource,
|
189
|
+
'component': component,
|
190
|
+
'parents': parents
|
191
|
+
}
|
192
|
+
component_name_import_dispatch[component_name](args)
|
193
|
+
|
135
194
|
|
136
195
|
def cleanup_endpoint(project_id: int, endpoint_id: int, resource: EndpointsResource):
|
137
196
|
print(f"{bcolors.OKBLUE}Cleaning up partial import...{bcolors.ENDC}")
|
@@ -114,9 +114,13 @@ class OpenApiEndpointAdapter():
|
|
114
114
|
operation = path[http_method]
|
115
115
|
required_query_params = []
|
116
116
|
required_body_params = []
|
117
|
+
literal_query_params = []
|
117
118
|
|
118
119
|
parameters = operation.get("parameters", {})
|
119
120
|
for parameter in parameters:
|
121
|
+
if '$ref' in parameter.keys():
|
122
|
+
parameter = self.__dereference(components, parameter['$ref'])
|
123
|
+
|
120
124
|
if parameter['in'] == 'query':
|
121
125
|
# query_param: RequestComponentName = {}
|
122
126
|
# query_param['name'] = parameter['name']
|
@@ -131,39 +135,10 @@ class OpenApiEndpointAdapter():
|
|
131
135
|
if not endpoint.get('query_param_names'):
|
132
136
|
endpoint['query_param_names'] = []
|
133
137
|
|
134
|
-
schema = parameter
|
135
|
-
|
136
|
-
|
137
|
-
param_value = None
|
138
|
-
if open_api_type == 'array':
|
139
|
-
item_type = schema['items']['type']
|
140
|
-
default_value = schema['items'].get('default')
|
141
|
-
item_default = None
|
142
|
-
if default_value:
|
143
|
-
item_default = {'value': default_value}
|
144
|
-
else:
|
145
|
-
item_default = {'value': self.__open_api_to_default_python_type(item_type)}
|
146
|
-
|
147
|
-
param_value = [item_default]
|
138
|
+
schema = parameter.get('schema', {})
|
139
|
+
self.__extract_param_properties(components, required_query_params, {parameter['name']: schema}, literal_query_params, curr_id=len(literal_query_params)+1)
|
148
140
|
|
149
|
-
|
150
|
-
else:
|
151
|
-
default_value = schema.get('default')
|
152
|
-
if default_value:
|
153
|
-
param_value = default_value
|
154
|
-
else:
|
155
|
-
param_value = self.__open_api_to_default_python_type(open_api_type)
|
156
|
-
|
157
|
-
literal_query_param = {
|
158
|
-
parameter['name']: {
|
159
|
-
'value': param_value,
|
160
|
-
'required': parameter.get('required', False),
|
161
|
-
}
|
162
|
-
}
|
163
|
-
|
164
|
-
if not endpoint.get('literal_query_params'):
|
165
|
-
endpoint['literal_query_params'] = {}
|
166
|
-
endpoint['literal_query_params'].update(literal_query_param)
|
141
|
+
endpoint['literal_query_params'] = literal_query_params
|
167
142
|
|
168
143
|
elif parameter['in'] == 'header':
|
169
144
|
header: RequestComponentName = {}
|
@@ -206,39 +181,16 @@ class OpenApiEndpointAdapter():
|
|
206
181
|
request_body = operation.get("requestBody", {})
|
207
182
|
required_request_body = request_body.get("required")
|
208
183
|
required_body_params = []
|
209
|
-
literal_body_params =
|
210
|
-
request_body_array = False
|
184
|
+
literal_body_params = []
|
211
185
|
|
212
186
|
content = request_body.get("content", {})
|
213
187
|
for mimetype, media_type in content.items():
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
# If Spec Component reference, look it up in components
|
218
|
-
if '$ref' in schema:
|
219
|
-
reference = schema['$ref']
|
220
|
-
self.__dereference(components, reference, required_body_params, literal_body_params)
|
221
|
-
else:
|
222
|
-
required_body_params = schema.get('required', [])
|
188
|
+
schema = media_type.get('schema')
|
189
|
+
if schema:
|
190
|
+
self.__extract_param_properties(components, required_body_params, {'tmp': schema}, literal_body_params)
|
223
191
|
|
224
|
-
|
225
|
-
|
226
|
-
if schema_type == 'object':
|
227
|
-
param_properties = schema.get('properties', {})
|
228
|
-
elif schema_type == 'array':
|
229
|
-
request_body_array = True
|
230
|
-
param_properties = {'tmp': schema['items']}
|
231
|
-
|
232
|
-
for property_key, property_value in param_properties.items():
|
233
|
-
if property_key in required_body_params:
|
234
|
-
param_properties[property_key]['required'] = True
|
235
|
-
|
236
|
-
if not endpoint.get('literal_body_params'):
|
237
|
-
endpoint['literal_body_params'] = {}
|
238
|
-
|
239
|
-
self.__extract_param_properties(components, None, required_body_params, param_properties, literal_body_params)
|
240
|
-
|
241
|
-
endpoint['literal_body_params'] = literal_body_params
|
192
|
+
if literal_body_params:
|
193
|
+
endpoint['literal_body_params'] = literal_body_params
|
242
194
|
|
243
195
|
# Only support first media type
|
244
196
|
break
|
@@ -249,10 +201,7 @@ class OpenApiEndpointAdapter():
|
|
249
201
|
|
250
202
|
literal_body_params = endpoint.get('literal_body_params')
|
251
203
|
if literal_body_params:
|
252
|
-
|
253
|
-
self.__convert_literal_component_param(endpoint, required_body_params, literal_body_params, 'body_param_name', 'literal_body_params')
|
254
|
-
else:
|
255
|
-
self.__convert_literal_component_param(endpoint, required_body_params, [literal_body_params], 'body_param_name', 'literal_body_params')
|
204
|
+
self.__convert_literal_component_param(endpoint, required_body_params, literal_body_params, 'body_param_name', 'literal_body_params')
|
256
205
|
|
257
206
|
# Responses -> construct lists of response header and response param name resources
|
258
207
|
responses = operation.get('responses', {})
|
@@ -332,74 +281,90 @@ class OpenApiEndpointAdapter():
|
|
332
281
|
|
333
282
|
return list(literal_params)[-2]
|
334
283
|
|
335
|
-
def __extract_param_properties(self, components,
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
flatten: bool = False
|
284
|
+
def __extract_param_properties(self, components, required_component_params, schema_object, literal_component_params, curr_id=0, parent_id=None, parent=None, query_string=''):
|
285
|
+
# Name of the schema object (i.e. the name of the body_param_name or response_param_name component)
|
286
|
+
property_name = list(schema_object.keys())[0]
|
340
287
|
|
341
|
-
|
342
|
-
|
343
|
-
if property_name not in literal_body_params:
|
344
|
-
literal_body_params[property_name] = {'value': {}}
|
288
|
+
# The actual OpenAPI schema object
|
289
|
+
property_schema = list(schema_object.values())[0]
|
345
290
|
|
346
|
-
|
347
|
-
|
291
|
+
if '$ref' in property_schema.keys():
|
292
|
+
property_schema = self.__dereference(components, property_schema.get('$ref'))
|
348
293
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
294
|
+
# Generates the entire query string for this particular property (ex: Pets[*].name for property 'name' of a 'Pet' element in the 'Pets' array
|
295
|
+
if property_name == 'tmp':
|
296
|
+
query = query_string
|
297
|
+
else:
|
298
|
+
if property_name.endswith('Element'):
|
299
|
+
query = f"{query_string}[*]"
|
300
|
+
elif query_string == '':
|
301
|
+
query = property_name
|
302
|
+
else:
|
303
|
+
query = f"{query_string}.{property_name}"
|
355
304
|
|
356
|
-
|
357
|
-
|
305
|
+
# A schema is traversable if it has one more non-empty nested schema objects
|
306
|
+
traversable = property_schema.get('properties') or property_schema.get('items') or property_schema.get('allOf')
|
307
|
+
|
308
|
+
if not traversable:
|
309
|
+
# Ex: {'name': {'type': 'string', 'description': 'Name of pet', 'Example': 'Buddy'}}
|
310
|
+
if property_name != 'tmp':
|
311
|
+
literal_val_type = self.__open_api_to_default_python_type(property_schema.get('type', 'object'))
|
312
|
+
literal_val = {'name': property_name, 'value': literal_val_type, 'required': property_schema.get('required', False), 'query': query, 'id': curr_id, 'parent_id': parent_id}
|
313
|
+
literal_component_params.append(literal_val)
|
314
|
+
return curr_id
|
315
|
+
|
316
|
+
if 'properties' in property_schema.keys():
|
317
|
+
# Ex: {'tmp': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string'}, 'tag': {'type': 'string'}}}}
|
318
|
+
required_component_params += property_schema.get('required', [])
|
319
|
+
|
320
|
+
# curr_id_tmp is the parent_id of all elements in param_properties
|
321
|
+
# Should be set to parent_id when property_name is 'tmp' to handle case where a schema uses the 'allOf' keyword since curr_id will change between every recursive call on each 'part' element in the allOf list
|
322
|
+
curr_id_tmp = parent_id if property_name == 'tmp' else curr_id
|
323
|
+
|
324
|
+
literal_val = parent if property_name == 'tmp' else {'name': property_name, 'value': {}, 'required': property_schema.get('schema_required', False), 'query': query, 'id': curr_id, 'parent_id': parent_id}
|
325
|
+
|
326
|
+
if property_name != 'tmp':
|
327
|
+
literal_component_params.append(literal_val)
|
328
|
+
|
329
|
+
param_properties = property_schema.get('properties')
|
330
|
+
for property_key, property_value in param_properties.items():
|
331
|
+
if property_key in required_component_params:
|
332
|
+
if property_value.get('type') == 'object':
|
333
|
+
# Necessary to avoid overwriting the 'required' list of an object-type schema
|
334
|
+
property_value['schema_required'] = True
|
335
|
+
else:
|
358
336
|
property_value['required'] = True
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
if property_name not in literal_body_params:
|
368
|
-
literal_body_params[property_name] = {'value': []}
|
369
|
-
if property_type_dict.get('required') == True:
|
370
|
-
literal_body_params[property_name]['required'] = True
|
371
|
-
|
372
|
-
self.__extract_param_properties(components, reference, required_body_params, param_properties, literal_body_params, nested_parameters=True)
|
373
|
-
|
337
|
+
required_component_params.remove(property_key)
|
338
|
+
curr_id = self.__extract_param_properties(components, required_component_params, {property_key: property_value}, literal_component_params, curr_id=curr_id+1, parent_id=curr_id_tmp, parent=literal_val, query_string=query)
|
339
|
+
|
340
|
+
elif property_schema.get('type') == 'array':
|
341
|
+
# Ex: {'tmp': {'type': 'array', 'items': {'$ref': '#/components/schemas/NewPet'}}}
|
342
|
+
if property_name == 'tmp':
|
343
|
+
schema_object = {"Element": property_schema['items']}
|
344
|
+
curr_id = self.__extract_param_properties(components, required_component_params, schema_object, literal_component_params, curr_id=curr_id+1, parent_id=parent_id, parent=parent, query_string=query)
|
374
345
|
else:
|
375
|
-
|
376
|
-
literal_val = {'value':
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
elif type(literal_body_params[most_recent_param]['value']) is list:
|
396
|
-
literal_body_params[most_recent_param]['value'].append(literal_val)
|
397
|
-
else:
|
398
|
-
literal_body_params[property_name] = literal_val
|
399
|
-
|
400
|
-
literal_body_params.pop('tmp', None)
|
346
|
+
schema_object = {f"{property_name}Element": property_schema['items']}
|
347
|
+
literal_val = {'name': property_name, 'value': [], 'required': property_schema.get('required', False), 'query': query, 'id': curr_id, 'parent_id': parent_id}
|
348
|
+
literal_component_params.append(literal_val)
|
349
|
+
curr_id = self.__extract_param_properties(components, required_component_params, schema_object, literal_component_params, curr_id=curr_id+1, parent_id=curr_id, parent=parent, query_string=query)
|
350
|
+
|
351
|
+
elif 'allOf' in property_schema.keys():
|
352
|
+
# Ex: {'Element': {'type': 'object', 'allOf': [{'$ref': '#/components/schemas/NewPet'}, {'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'integer', 'format': 'int64'}}}]}}
|
353
|
+
all_of = property_schema.get('allOf')
|
354
|
+
literal_val = parent if property_name == 'tmp' else {'name': property_name, 'value': {}, 'required': property_schema.get('self_required', False), 'query': query, 'id': curr_id, 'parent_id': parent_id}
|
355
|
+
if property_name != 'tmp':
|
356
|
+
literal_component_params.append(literal_val)
|
357
|
+
|
358
|
+
curr_id_tmp = parent_id if property_name == 'tmp' else curr_id
|
359
|
+
for part in all_of:
|
360
|
+
required_component_params = part.get('required', [])
|
361
|
+
curr_id = self.__extract_param_properties(components, required_component_params, {'tmp': part}, literal_component_params, curr_id=curr_id, parent_id=curr_id_tmp, parent=literal_val, query_string=query)
|
362
|
+
|
363
|
+
return curr_id
|
364
|
+
|
401
365
|
|
402
|
-
|
366
|
+
# Returns the schema object located at the given reference path
|
367
|
+
def __dereference(self, components: Spec, reference: str):
|
403
368
|
# '#/components/schemas/NewPet'
|
404
369
|
if not reference.startswith('#'):
|
405
370
|
print('external references are not supported yet')
|
@@ -412,55 +377,13 @@ class OpenApiEndpointAdapter():
|
|
412
377
|
component_name = component_data[1]
|
413
378
|
component = components.get(component_type, {})
|
414
379
|
|
415
|
-
# If component_type is 'headers'
|
416
|
-
# Example: '#components/headers/X-RateLimit-Limit'
|
417
|
-
if component_type == "headers":
|
418
|
-
# In this case, literal_body_params represents a header rather than request or response body params
|
419
|
-
literal_body_params['name'] = component_name
|
420
|
-
header_example = component.get('example')
|
421
|
-
if header_example:
|
422
|
-
literal_body_params['values'].append(header_example)
|
423
|
-
literal_body_params['is_required'] = component.get('is_required', False)
|
424
|
-
literal_body_params['is_deterministic'] = True
|
425
|
-
return literal_body_params
|
426
|
-
|
427
380
|
# Example: {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string'}, 'tag': {'type': 'string'}}}
|
428
381
|
body_spec = component.content()[component_name]
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
if schema_type == 'object':
|
435
|
-
param_properties = body_spec.get('properties', {})
|
436
|
-
elif schema_type == 'array':
|
437
|
-
param_properties = {'tmp': body_spec['items']}
|
438
|
-
|
439
|
-
all_of = body_spec.get('allOf')
|
440
|
-
any_of = body_spec.get('anyOf')
|
441
|
-
one_of = body_spec.get('oneOf')
|
442
|
-
|
443
|
-
if param_properties:
|
444
|
-
for param_prop_key, param_prop_val in param_properties.items():
|
445
|
-
if param_prop_key in required_body_params:
|
446
|
-
param_prop_val['required'] = True
|
447
|
-
required_body_params.remove(param_prop_key)
|
448
|
-
|
449
|
-
self.__extract_param_properties(components, None, required_body_params, param_properties, literal_body_params, nested_parameters=nested_parameters)
|
450
|
-
|
451
|
-
elif all_of:
|
452
|
-
for part in all_of:
|
453
|
-
required_body_params = part.get('required', [])
|
454
|
-
nested_reference = part.get('$ref')
|
455
|
-
if nested_reference:
|
456
|
-
self.__extract_param_properties(components, nested_reference, required_body_params, {'tmp': part}, literal_body_params)
|
457
|
-
else:
|
458
|
-
self.__extract_param_properties(components, None, required_body_params, {'tmp': part}, literal_body_params)
|
459
|
-
|
460
|
-
# TODO
|
461
|
-
# elif any_of or one_of:
|
462
|
-
|
463
|
-
return param_properties
|
382
|
+
|
383
|
+
if '$ref' in body_spec.keys():
|
384
|
+
body_spec = self.__dereference(components, body_spec.get('$ref'))
|
385
|
+
|
386
|
+
return body_spec
|
464
387
|
|
465
388
|
def __convert_literal_component_param(self, endpoint: EndpointShowResponse,
|
466
389
|
required_component_params: List[str], literal_component_params: Union[dict, list],
|
@@ -608,32 +531,14 @@ class OpenApiEndpointAdapter():
|
|
608
531
|
continue
|
609
532
|
|
610
533
|
# Construct response param name components
|
611
|
-
literal_response_params =
|
612
|
-
response_body_array = False
|
534
|
+
literal_response_params = []
|
613
535
|
required_response_params = []
|
614
536
|
response_content = response_definition.get('content', {})
|
615
537
|
for mimetype, media_type in response_content.items():
|
616
|
-
|
617
|
-
|
538
|
+
schema = media_type.get('schema')
|
539
|
+
if schema:
|
540
|
+
self.__extract_param_properties(components, required_response_params, {'tmp': schema}, literal_response_params)
|
618
541
|
|
619
|
-
if '$ref' in schema:
|
620
|
-
reference = schema['$ref']
|
621
|
-
self.__dereference(components, reference, required_response_params, literal_response_params)
|
622
|
-
else:
|
623
|
-
schema_type = schema.get('type')
|
624
|
-
if schema_type:
|
625
|
-
if schema_type == 'object':
|
626
|
-
param_properties = schema.get('properties', {})
|
627
|
-
elif schema_type == 'array':
|
628
|
-
response_body_array = True
|
629
|
-
param_properties = {'tmp': schema['items']}
|
630
|
-
|
631
|
-
for property_key, property_value in param_properties.items():
|
632
|
-
if property_key in required_response_params:
|
633
|
-
param_properties[property_key]['required'] = True
|
634
|
-
|
635
|
-
self.__extract_param_properties(components, None, required_response_params, param_properties, literal_response_params)
|
636
|
-
|
637
542
|
if literal_response_params:
|
638
543
|
endpoint['literal_response_params'] = literal_response_params
|
639
544
|
|
@@ -642,10 +547,7 @@ class OpenApiEndpointAdapter():
|
|
642
547
|
|
643
548
|
literal_response_params = endpoint.get('literal_response_params')
|
644
549
|
if literal_response_params:
|
645
|
-
|
646
|
-
self.__convert_literal_component_param(endpoint, required_response_params, literal_response_params, 'response_param_name', 'literal_response_params')
|
647
|
-
else:
|
648
|
-
self.__convert_literal_component_param(endpoint, required_response_params, [literal_response_params], 'response_param_name', 'literal_response_params')
|
550
|
+
self.__convert_literal_component_param(endpoint, required_response_params, literal_response_params, 'response_param_name', 'literal_response_params')
|
649
551
|
|
650
552
|
# Construct response header name components
|
651
553
|
response_headers = response_definition.get('headers', {})
|
@@ -654,14 +556,13 @@ class OpenApiEndpointAdapter():
|
|
654
556
|
response_header_name['name'] = header_name
|
655
557
|
|
656
558
|
if '$ref' in header_definition:
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
response_header_name['is_deterministic'] = True
|
559
|
+
header_definition = self.__dereference(components, header_definition.get('$ref'))
|
560
|
+
|
561
|
+
header_example = header_definition.get('example')
|
562
|
+
if header_example:
|
563
|
+
response_header_name['value']= header_example
|
564
|
+
response_header_name['is_required'] = header_definition.get('is_required', False)
|
565
|
+
response_header_name['is_deterministic'] = True
|
665
566
|
|
666
567
|
if not endpoint.get('response_header_names'):
|
667
568
|
endpoint['response_header_names'] = []
|