def convert_field_info_to_swagger_parameter(self, param_type, input_parameter_obj, type_dict, structure_svc, enum_svc, show_unreleased_apis): """ Converts metamodel fieldinfo to swagger parameter. """ parameter_obj = {} ref_path = "#/definitions/" tpHandler = RestTypeHandler(show_unreleased_apis) tpHandler.visit_type_category(input_parameter_obj.type, parameter_obj, type_dict, structure_svc, enum_svc, ref_path) if 'required' not in parameter_obj: parameter_obj['required'] = True parameter_obj['in'] = param_type parameter_obj['name'] = input_parameter_obj.name parameter_obj['description'] = input_parameter_obj.documentation # $ref should be encapsulated in 'schema' instead of parameter. -> this throws swagger validation error # hence another method is to to get data in $ref in parameter_obj # itself if '$ref' in parameter_obj: type_obj = type_dict[parameter_obj['$ref'][len(ref_path):]] description = parameter_obj['description'] if 'description' in type_obj: description = "" description = "{ 1. " + type_obj['description'] + \ " }, { 2. " + parameter_obj['description'] + " }" parameter_obj.update(type_obj) parameter_obj['description'] = description del parameter_obj['$ref'] return parameter_obj
def wrap_body_params( self, service_name, operation_name, body_param_list, type_dict, structure_svc, enum_svc, show_unreleased_apis): """ Creates a json object wrapper around request body parameters. parameter names are used as keys and the parameters as values. For instance, datacenter create operation takes CreateSpec whose parameter name is spec. This method creates a json wrapper object datacenter.create { 'spec' : {spec obj representation } } """ # todo: # not unique enough. make it unique wrapper_name = service_name + '_' + operation_name body_obj = {} properties_obj = {} body_obj['type'] = 'object' body_obj['properties'] = properties_obj required = [] ref_path = "#/components/schemas/" tpHandler = RestTypeHandler(show_unreleased_apis) for param in body_param_list: parameter_obj = {} tpHandler.visit_type_category( param.type, parameter_obj, type_dict, structure_svc, enum_svc, ref_path) parameter_obj['description'] = param.documentation properties_obj[param.name] = parameter_obj if 'required' not in parameter_obj: required.append(param.name) elif parameter_obj['required'] == 'true': required.append(param.name) if 'requestBodies' not in type_dict: type_dict['requestBodies'] = {} type_dict['requestBodies'][wrapper_name] = { 'content': { 'application/json': { 'schema': { '$ref': ref_path + wrapper_name } } } } type_dict[wrapper_name] = body_obj parameter_obj = {'$ref': "#/components/requestBodies/" + wrapper_name} return parameter_obj
def wrap_body_params( self, service_name, operation_name, body_param_list, type_dict, structure_svc, enum_svc, enable_filtering): """ Creates a json object wrapper around request body parameters. parameter names are used as keys and the parameters as values. For instance, datacenter create operation takes CreateSpec whose parameter name is spec. This method creates a json wrapper object datacenter.create { 'spec' : {spec obj representation } } """ # todo: # not unique enough. make it unique wrapper_name = service_name + '_' + operation_name body_obj = {} properties_obj = {} body_obj['type'] = 'object' body_obj['properties'] = properties_obj required = [] ref_path = "#/definitions/" tpHandler = RestTypeHandler() for param in body_param_list: parameter_obj = {} tpHandler.visit_type_category( param.type, parameter_obj, type_dict, structure_svc, enum_svc, ref_path, enable_filtering) parameter_obj['description'] = param.documentation properties_obj[param.name] = parameter_obj if 'required' not in parameter_obj: required.append(param.name) elif parameter_obj['required'] == 'true': required.append(param.name) parameter_obj = {'in': 'body', 'name': 'request_body'} if len(required) > 0: body_obj['required'] = required parameter_obj['required'] = True elif 'required' in body_obj: del body_obj['required'] type_dict[wrapper_name] = body_obj schema_obj = {'$ref': ref_path + wrapper_name} parameter_obj['schema'] = schema_obj return parameter_obj
class TestRestTypeHandler(unittest.TestCase): # Showing unreleased apis (disabled filtering) rest_tphandler = RestTypeHandler(True) def test_visit_generic(self): # case 1: when generic instantiation type is 'SET' and category is 'BUILT-IN' generic_instantiation_element_type_mock = mock.Mock() generic_instantiation_element_type_mock.category = 'BUILTIN' generic_instantiation_element_type_mock.builtin_type = 'date-time' generic_instantiation_mock = mock.Mock() generic_instantiation_mock.generic_type = 'SET' generic_instantiation_mock.element_type = generic_instantiation_element_type_mock field_info_mock = mock.Mock() field_info_type = mock.Mock() field_info_type.category = 'BUILTIN' field_info_type.builtin_type = 'date-time' field_info_mock.type = field_info_type field_info_mock.generic_instantiation = generic_instantiation_mock field_info_mock.documentation = 'fieldInfoMockDescription' field_info_mock.name = 'fieldInfoMockName' field_info_mock.metadata = {} structure_info_mock = mock.Mock() structure_info_mock.fields = [field_info_mock] structure_dict = { 'com.vmware.package.mock': structure_info_mock } ''' The structure dict looks like: structure_dict = { 'com.vmware.package.mock': StructureInfo( fields = [ FieldInfo( name = 'fieldInfoMockName', documentation = 'fieldInfoMockDescription', generic_instantiation = GenericInstantiation( generic_type = 'SET', element_type = Type( category = 'BUILTIN', builtin_type = 'date-time')) )]) } ''' enum_dict = {} type_dict = {} new_prop = {} self.rest_tphandler.visit_generic(generic_instantiation_mock, new_prop, type_dict, structure_dict, enum_dict, '#/definitions/') new_prop_expected = {'type': 'array', 'uniqueItems': True, 'items': {'type': 'date-time'}} self.assertEqual(new_prop_expected, new_prop) # case 2: when generic instantiation type is 'OPTIONAL' and category is 'BUILT-IN' generic_instantiation_mock.generic_type = 'OPTIONAL' enum_dict = {} type_dict = {} new_prop = {} self.rest_tphandler.visit_generic(generic_instantiation_mock, new_prop, type_dict, structure_dict, enum_dict, '#/definitions/') new_prop_expected = {'required': False, 'type': 'date-time'} self.assertEqual(new_prop_expected, new_prop) # case 3: when generic instantiation type is 'LIST' and category is 'USER-DEFINED' generic_instantiation_mock.generic_type = 'LIST' user_defined_type_mock = mock.Mock() user_defined_type_mock.resource_type = 'com.vmware.vapi.structure' user_defined_type_mock.resource_id = 'com.vmware.package.mock' generic_instantiation_element_type_mock.category = 'USER_DEFINED' generic_instantiation_element_type_mock.user_defined_type = user_defined_type_mock ''' The structure dict looks like: structure_dict = { 'com.vmware.package.mock': StructureInfo( fields = [ FieldInfo( name = 'fieldInfoMockName', documentation = 'fieldInfoMockDescription', generic_instantiation = GenericInstantiation( generic_type = 'LIST', element_type = Type( category = 'USER_DEFINED', user_defined_type = UserDefinedType( resource_type = 'com.vmware.vapi.structure', resource_id = 'com.vmware.package.mock' ))) )]) } ''' enum_dict = {} type_dict = {} new_prop = {} self.rest_tphandler.visit_generic(generic_instantiation_mock, new_prop, type_dict, structure_dict, enum_dict, '#/definitions/') new_prop_expected = {'type': 'array', 'items': {'$ref': '#/definitions/com.vmware.package.mock'}} self.assertEqual(new_prop_expected, new_prop) # case 4: when generic instantiation type is 'MAP' # case 4.1: map key and value type is 'BUILTIN' map_key_type_mock = mock.Mock() map_key_type_mock.category = 'BUILTIN' map_key_type_mock.builtin_type = 'long' map_value_type_mock = mock.Mock() map_value_type_mock.category = 'BUILTIN' map_value_type_mock.builtin_type = 'long' generic_instantiation_mock = mock.Mock() generic_instantiation_mock.generic_type = 'MAP' generic_instantiation_mock.map_key_type = map_key_type_mock generic_instantiation_mock.map_value_type = map_value_type_mock ''' The structure dict looks like: structure_dict = { 'com.vmware.package.mock': StructureInfo( fields = [ FieldInfo( name = 'fieldInfoMockName', documentation = 'fieldInfoMockDescription', generic_instantiation = GenericInstantiation( generic_type = 'MAP', map_key_type = MapKeyType( category = 'BUILTIN', builtin_type = 'long'), map_value_type = MapValueType( category = 'BUILTIN', builtin_type = 'long') ) )]) } ''' enum_dict = {} type_dict = {} new_prop = {} self.rest_tphandler.visit_generic(generic_instantiation_mock, new_prop, type_dict, structure_dict, enum_dict, '#/definitions/') new_prop_expected = { 'type': 'array', 'items': { 'type': 'object', 'properties': { 'key': {'type': 'integer'}, 'value': {'type': 'integer'} } } } self.assertEqual(new_prop_expected, new_prop) # case 4.2: map key and value type is 'USER_DEFINED' map_key_type_mock.category = 'USER_DEFINED' map_key_type_mock.user_defined_type = user_defined_type_mock map_value_type_mock.category = 'USER_DEFINED' map_value_type_mock.user_defined_type = user_defined_type_mock type_dict = { 'com.vmware.package.mock': {} } new_prop = {} self.rest_tphandler.visit_generic(generic_instantiation_mock, new_prop, type_dict, structure_dict, enum_dict, '#/definitions/') new_prop_expected = { 'type': 'array', 'items': { 'type': 'object', 'properties': { 'key': {'$ref': '#/definitions/com.vmware.package.mock'}, 'value': {'$ref': '#/definitions/com.vmware.package.mock'} } } } self.assertEqual(new_prop_expected, new_prop) # case 4.3: map key and value type is 'GENERIC' generic_instantiation_element_type_mock.category = 'BUILTIN' generic_instantiation_element_type_mock.builtin_type = 'double' generic_instantiation_map_value_type_mock = mock.Mock() generic_instantiation_map_value_type_mock.generic_type = 'OPTIONAL' generic_instantiation_map_value_type_mock.element_type = generic_instantiation_element_type_mock map_key_type_mock.category = 'BUILTIN' map_key_type_mock.builtin_type = 'string' map_value_type_mock.category = 'GENERIC' map_value_type_mock.generic_instantiation = generic_instantiation_map_value_type_mock new_prop = {} self.rest_tphandler.visit_generic(generic_instantiation_mock, new_prop, type_dict, structure_dict, enum_dict, '#/definitions/') new_prop_expected = { 'type': 'array', 'items': { 'type': 'object', 'properties': { 'key': {'type': 'string'}, 'value': { 'required': False, 'type': 'number', 'format': 'double' } } } } self.assertEqual(new_prop_expected, new_prop)
def populate_response_map(self, output, errors, http_error_map, type_dict, structure_svc, enum_svc, service_id, operation_id, enable_filtering): response_map = {} ref_path = "#/definitions/" success_response = {'description': output.documentation} schema = {} tpHandler = RestTypeHandler() tpHandler.visit_type_category(output.type, schema, type_dict, structure_svc, enum_svc, ref_path, enable_filtering) # if type of schema is void, don't include it. # this prevents showing response as void in swagger-ui if schema is not None: if not ('type' in schema and schema['type'] == 'void'): # Handling Value wrappers for /rest and /api resp = { 'type': 'object', 'properties': { 'value': schema }, 'required': ['value'] } if operation_id == 'get': type_name = service_id else: type_name = service_id + '.' + operation_id type_name = type_name + '_result' if type_name not in type_dict: type_dict[type_name] = resp resp = {"$ref": ref_path + type_name} success_response['schema'] = resp # success response is not mapped through metamodel. # hardcode it for now. response_map[requests.codes.ok] = success_response for error in errors: status_code = http_error_map.error_rest_map.get( error.structure_id, http_client.INTERNAL_SERVER_ERROR) tpHandler.check_type('com.vmware.vapi.structure', error.structure_id, type_dict, structure_svc, enum_svc, ref_path, enable_filtering) schema_obj = { 'type': 'object', 'properties': { 'type': { 'type': 'string' }, 'value': { '$ref': ref_path + error.structure_id } } } type_dict[error.structure_id + '_error'] = schema_obj response_obj = { 'description': error.documentation, 'schema': { '$ref': ref_path + error.structure_id + '_error' } } response_map[status_code] = response_obj return response_map
def flatten_query_param_spec(self, query_param_info, type_dict, structure_svc, enum_svc, show_unreleased_apis): """ Flattens query parameters specs. 1. Create a query parameter for every field in spec. Example 1: consider datacenter get which accepts optional filterspec. Optional<Datacenter.FilterSpec> filter) The method would convert the filterspec to 3 separate query parameters filter.datacenters, filter.names and filter.folders. Example 2: consider /vcenter/deployment/install/initial-config/remote-psc/thumbprint get which accepts parameter vcenter.deployment.install.initial_config.remote_psc.thumbprint.remote_spec. The two members defined under remote_spec address and https_port are converted to two separate query parameters address(required) and https_port(optional). 2. The field info is simple type. i.e the type is string, integer then it is converted it to swagger parameter. Example: consider /com/vmware/content/library/item get which accepts parameter 'library_id'. The field is converted to library_id query parameter. 3. This field has references to a spec but the spec is not a complex type and does not have property 'properties'. i.e the type is string, integer. The members defined under the spec are converted to query parameter. Example: consider /appliance/update/pending get which accepts two parameter 'source_type' and url. Where source_type is defined in the spec 'appliance.update.pending.source_type' and field url is of type string. The fields 'source_type' and 'url' are converted to query parameter of type string. """ prop_array = [] parameter_obj = {} ref_path = "#/components/schemas/" tpHandler = RestTypeHandler(show_unreleased_apis) tpHandler.visit_type_category(query_param_info.type, parameter_obj, type_dict, structure_svc, enum_svc, ref_path) if '$ref' in parameter_obj: reference = parameter_obj['$ref'].replace(ref_path, '') type_ref = type_dict.get(reference, None) if type_ref is None: return None if 'properties' in type_ref: for property_name, property_value in six.iteritems( type_ref['properties']): prop = { 'in': 'query', 'name': query_param_info.name + '.' + property_name } prop['schema'] = {} if 'type' in property_value: prop['schema']['type'] = property_value['type'] if property_value['type'] == 'array': prop['schema']['items'] = property_value['items'] if '$ref' in property_value['items']: ref = property_value['items']['$ref'].replace( ref_path, '') type_ref = type_dict[ref] prop['schema']['items'] = type_ref if 'description' in prop['schema']['items']: del prop['schema']['items']['description'] if 'description' in property_value: prop['description'] = property_value['description'] elif '$ref' in property_value: reference = property_value['$ref'].replace( ref_path, '') prop_obj = type_dict[reference] prop['schema'] = prop_obj if 'required' in type_ref: if property_name in type_ref['required']: prop['required'] = True else: prop['required'] = False prop_array.append(prop) else: prop = { 'in': 'query', 'name': query_param_info.name, 'description': type_ref['description'], 'schema': type_ref } prop_array.append(prop) else: parameter_obj['in'] = 'query' parameter_obj['name'] = query_param_info.name parameter_obj['description'] = query_param_info.documentation if 'required' not in parameter_obj: parameter_obj['required'] = True parameter_obj['schema'] = {"type": parameter_obj['type']} del parameter_obj['type'] prop_array.append(parameter_obj) return prop_array