def _get_schema(self, multiple=False, inline=False, request=False): required = [] properties = OrderedDict() schema = OrderedDict() if not inline: schema['id'] = self.name schema['type'] = 'object' for field_name, obj in self.fields.items(): field_object = obj.get('request') if request else obj.get('response') if request and (obj.get('readOnly') or field_object.get('readOnly')): continue if obj.get('required') or field_object.get('required'): required.append(field_name) properties[field_name] = field_object schema['required'] = required schema['properties'] = properties result = OrderedDict() if multiple: result['type'] = 'array' result['items'] = OrderedDict(schema=schema) else: result = OrderedDict(schema=schema) return result
def parameters(self): parameters = super(DjangoFilterBackendIntrospector, self).parameters filter_fields = getattr(self.view, 'filter_fields', []) for field_name in filter_fields: parameters.append( OrderedDict({ 'in': 'query', 'name': field_name, 'type': 'string', 'required': False, 'description': 'Filter parameter' })) parameters.append( OrderedDict({ 'in': 'query', 'name': 'o', 'description': 'Ordering parameter', 'type': 'string', 'enum': list(filter_fields) + list(map(lambda f: '-{0}'.format(f), filter_fields)) })) return parameters
def parameters(self): """ Collects pagination parameters from pagination class :return: Parameters array :rtype: list """ parameters = super(LimitOffsetPaginationIntrospector, self).parameters limit_query_param = getattr(self._instance, 'limit_query_param', None) offset_query_param = getattr(self._instance, 'offset_query_param', None) default_limit = getattr(self._instance, 'default_limit', None) if limit_query_param: parameters.append( OrderedDict([ ('in', 'query'), ('name', limit_query_param), ('type', 'string'), ('description', 'Limit parameter (default={})'.format(default_limit)), ('required', False), ])) if offset_query_param: parameters.append( OrderedDict([ ('in', 'query'), ('name', offset_query_param), ('type', 'integer'), ('description', 'Offset parameter'), ('required', False), ])) return parameters
def test_parameters(self): expected_parameters = [ OrderedDict([('in', 'query'), ('name', u'limit'), ('type', 'string'), ('description', 'Limit parameter (default=None)'), ('required', False)]), OrderedDict([('in', 'query'), ('name', u'offset'), ('type', 'integer'), ('description', 'Offset parameter'), ('required', False)]) ] parameters = self.introspector.parameters self.assertEqual(parameters, expected_parameters)
def test_prepare_field(self): expected_field_obj = OrderedDict([ ('required', False), ('readOnly', False), ('response', OrderedDict([('type', 'string'), ('enum', ['a', 'b'])])), ('request', OrderedDict([('type', 'string'), ('enum', ['a', 'b'])])) ]) field = self.serializer.fields.fields['choices_field'] self.field_introspector = FieldIntrospector(field, SerializerIntrospector) field_obj = self.field_introspector.prepare_field_object() self.assertEqual(expected_field_obj, field_obj)
def test_prepare_field_docstring(self): expected_field_obj = OrderedDict([ ('required', True), ('readOnly', False), ('response', OrderedDict([('type', 'string')])), ('request', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string')]))])) ]) field = self.serializer.fields.fields['custom_field'] self.field_introspector = FieldIntrospector(field, SerializerIntrospector) field_obj = self.field_introspector.prepare_field_object() self.assertEqual(expected_field_obj, field_obj)
def _operation(introspector): operation = OrderedDict( tags=introspector.tags, summary=introspector.parser.get_summary(), description=introspector.parser.get_description(), parameters=introspector.parameters, responses=introspector.responses, security=introspector.security) # Remove empty keys for key, value in list(operation.items()): if not value: operation.pop(key) return operation
def security_definitions(self): """ Collects authentication security definitions :return: authentication security definitions :rtype: dict """ security_definitions = super(TokenAuthenticationIntrospector, self).security_definitions security_definitions.update( OrderedDict({ self.name: { 'type': 'apiKey', 'name': 'Authorization', 'in': 'header', 'description': """Clients should authenticate by passing the token key in the "Authorization" HTTP header, prepended with the string "Token ". For example: Authorization: Token 401f7ac837da42b97f613d789819ff93537bee6a""" } })) return security_definitions
def test_security(self): expected_result = [ OrderedDict([('djangorestframework_token_authentication', [])]) ] instance = TestTokenAuthView() introspector = TokenAuthenticationIntrospector(instance) self.assertEqual(expected_result, introspector.security)
def test_parameters(self): expected_parameters = [ OrderedDict([('in', 'query'), ('name', u'page'), ('type', 'string'), ('description', 'Page parameter'), ('required', False)]) ] parameters = self.introspector.parameters self.assertEqual(parameters, expected_parameters)
def test_parameters(self): expected_result = [ OrderedDict({ 'in': 'query', 'name': 'test_filter_field_1', 'type': 'string', 'required': False, 'description': 'Filter parameter', }), OrderedDict({ 'in': 'query', 'name': 'test_filter_field_2', 'type': 'string', 'required': False, 'description': 'Filter parameter', }), OrderedDict({ 'in': 'query', 'name': 'o', 'type': 'string', 'description': 'Ordering parameter', 'enum': [ 'test_filter_field_1', 'test_filter_field_2', '-test_filter_field_1', '-test_filter_field_2' ], }), ] instance = TestDjangoFilterBackendView() introspector = DjangoFilterBackendIntrospector(instance, DjangoFilterBackend) self.assertEqual(sorted(expected_result[0]), sorted(introspector.parameters[0])) self.assertEqual(sorted(expected_result[1]), sorted(introspector.parameters[1])) self.assertEqual(sorted(expected_result[2]), sorted(introspector.parameters[2]))
def prepare_field_object(self): request, response = self._prepare_form_docstring() result = OrderedDict() result['required'] = getattr(self._field, 'required', False) result['readOnly'] = getattr(self._field, 'read_only', False) result['response'] = response or self._get_field_object() result['request'] = request or self._get_field_object(request=True) return result
def test_responses(self): expected_empty_responses = OrderedDict([ (200, OrderedDict([('description', 'Empty response')])) ]) empty_responses = self.method_introspector.responses self.assertEqual(empty_responses, expected_empty_responses) serializer_responses = self.method_introspector_empty.responses self.assertIn(200, serializer_responses) self.assertIn('description', serializer_responses[200]) self.assertIn('schema', serializer_responses[200]) list_responses = self.method_introspector_list.responses self.assertIn(200, list_responses) self.assertIn('description', list_responses[200]) self.assertIn('schema', list_responses[200]) expected_destroy_responses = OrderedDict([ (204, OrderedDict([('description', 'OK')])) ]) destroy_responses = self.method_introspector_destroy.responses self.assertEqual(destroy_responses, expected_destroy_responses)
def test_security_definitions(self): expected_result = OrderedDict([('basic_authentication', { 'type': 'basic', 'description': 'Clients should authenticate by passing the base64 encoded username:password string\n' ' in the "Authorization HTTP header, prepended with the string "Basic ".\n' ' For example:\n Authorization: Basic dXNlcjpwYXNzd29yZA==' })]) instance = TestBasicAuthView() introspector = BasicAuthenticationIntrospector(instance) self.assertEqual(expected_result, introspector.security_definitions)
def _prepare_docstring_field_object(field_object): result = OrderedDict() result['required'] = field_object.pop('required', False) result['readOnly'] = field_object.pop('readOnly', False) if 'response' not in field_object and 'request' not in field_object: result['request'] = field_object result['response'] = field_object else: result['request'] = field_object.get('request', field_object.get('response')) result['response'] = field_object.get('response', field_object.get('request')) return result
def get_operation(self): """ Get full swagger operation object :return: swagger operation object :rtype: OrderedDict """ operation = OrderedDict(tags=self.parser.get_tags(), summary=self.parser.get_summary(), description=self.parser.get_description(), parameters=self.parameters, produces=None, consumes=None, responses=self.responses, security=self.security) for key, value in list(operation.items()): # Remove empty keys if not value: operation.pop(key) return operation
def parameters(self): parameters = super(OrderingFilterBackendIntrospector, self).parameters ordering_fields = getattr(self.view, 'ordering_fields', []) ordering_param = getattr(self._instance, 'ordering_param', 'ordering') parameters.append( OrderedDict({ 'in': 'query', 'name': ordering_param, 'type': 'string', 'enum': ordering_fields })) return parameters
def responses(self): """ Create pagination responses :return: Reponses object :rtype: OrderedDict """ responses = super(BasePaginationIntrospector, self).responses if self.si: if self.response_fields: response = OrderedDict([ ('description', 'Pagination response'), ('schema', OrderedDict([('type', 'object'), ('id', '{}Paginator'.format(self.si.name)), ('required', []), ('properties', OrderedDict())])), ]) for field, field_type in self.response_fields: response['schema']['required'].append(field) if field == self.results_field: response['schema']['properties'][ field] = self.si.build_response_object( multiple=True) else: response['schema']['properties'][field] = OrderedDict( type=field_type) responses[200] = response else: responses[200] = OrderedDict([ ('description', 'Default response'), ('schema', self.si.build_response_object(multiple=True)), ]) return responses
def get_operation(self): """ Get full swagger operation object :return: swagger operation object :rtype: OrderedDict """ operation = OrderedDict(tags=self._get_tags(), summary=self._get_summary(), description=self._get_description(), parameters=self._get_parameters(), produces=self._get_produces(), consumes=self._get_consumes(), responses=self.responses, security=self._get_security()) # TODO: SECURITY OBJECT SECURITY DEFINITIONS for key, value in list(operation.items()): # Remove empty keys if not value: operation.pop(key) return operation
def test_parameters(self): expected_result = [ OrderedDict({ 'in': 'query', 'name': u'ordering', 'type': 'string', 'enum': ('test_filter_field_1', 'test_filter_field_2'), }) ] instance = TestOrderingFilterView() introspector = OrderingFilterBackendIntrospector( instance, OrderingFilter) self.assertEqual(expected_result, introspector.parameters)
def get_definitions(self): """ Return all serializer definitions found in api :return: definitions :rtype: dict """ definitions = OrderedDict() for serializer in set(self.serializers): si = SerializerIntrospector(serializer) definitions[si.name] = si.build_response_object( inline=True)['schema'] # tricky dumps and loads for django specific fields return json.loads(json.dumps(definitions, cls=LazyEncoder))
def _collect_fields(self): serializer_fields = self._get_serializer_fields() docstring_fields = self._get_docstring_fields() _fields = OrderedDict() fields_set = set(serializer_fields.keys()).union(docstring_fields.keys()) for field_name in fields_set: if field_name in docstring_fields: field_object = docstring_fields[field_name] _fields[field_name] = self._prepare_docstring_field_object(field_object) else: fi = FieldIntrospector(serializer_fields[field_name], self.__class__) _fields[field_name] = fi.prepare_field_object() return _fields
def test_security_definitions(self): expected_result = OrderedDict([('djangorestframework_token_authentication', { 'description': 'Clients should authenticate by passing the token key in the "Authorization"\n' ' HTTP header, prepended with the string "Token ". For example:\n' ' Authorization: Token 401f7ac837da42b97f613d789819ff93537bee6a', 'type': 'apiKey', 'name': 'Authorization', 'in': 'header' })]) instance = TestTokenAuthView() introspector = TokenAuthenticationIntrospector(instance) self.assertEqual(expected_result, introspector.security_definitions)
def _get_docstring_fields(self): """ Collect custom serializer fields described in serializer docstring :rtype: OrderedDict """ if not inspect.isclass(self.serializer): self.serializer = self.serializer.__class__ parser = YAMLDocstringParser() for cls in inspect.getmro(self.serializer): parser.update(inspect.getdoc(cls)) doc_fields = parser.schema.get('fields', OrderedDict()) return doc_fields
def parameters(self): """ Collects pagination parameters from pagination class :return: Parameters array :rtype: list """ parameters = super(PageNumberPaginationIntrospector, self).parameters page_query_param = getattr(self._instance, 'page_query_param', None) if page_query_param: parameters.append( OrderedDict([ ('in', 'query'), ('name', page_query_param), ('type', 'string'), ('description', 'Page parameter'), ('required', False), ])) return parameters
def security_definitions(self): """ Collects authentication security definitions :return: authentication security definitions :rtype: dict """ security_definitions = super(BasicAuthenticationIntrospector, self).security_definitions security_definitions.update( OrderedDict({ self.name: { 'type': 'basic', 'description': """Clients should authenticate by passing the base64 encoded username:password string in the "Authorization HTTP header, prepended with the string "Basic ". For example: Authorization: Basic dXNlcjpwYXNzd29yZA==""" } })) return security_definitions
def test_responses(self): expected_responses = OrderedDict([ (200, OrderedDict([ ('description', 'Pagination response'), ('schema', OrderedDict([ ('type', 'object'), ('id', 'TestSimpleSerializerPaginator'), ('required', ['count', 'next', 'previous', 'results']), ('properties', OrderedDict([ ('count', OrderedDict([('type', 'integer')])), ('next', OrderedDict([('type', 'string')])), ('previous', OrderedDict([('type', 'string')])), ('results', OrderedDict([ ('type', 'array'), ('items', OrderedDict([ ('schema', OrderedDict([ ('id', 'TestSimpleSerializer'), ('type', 'object'), ('required', []), ('properties', OrderedDict([('test_field', OrderedDict([ ('type', 'integer'), ('minimum', 0), ('maximum', 10), ('default', 5) ]))])) ])) ])) ])) ])) ])) ])) ]) responses = self.introspector.responses self.assertEqual(expected_responses, responses)
def _get_field_object(self, request=False): """ Creates swagger object for field for request or response :param request: is this object for request? :return: swagger object :rtype: OrderedDict """ if isinstance(self._field, BaseSerializer): if getattr(self._field, 'many', None): result = { 'type': 'array', 'items': self._serializer_inrospector_class( self._field).build_response_object(), } else: result = self._serializer_inrospector_class( self._field).build_response_object() else: field_type, data_type, data_format = self._get_field_type( self._field) if data_type == 'file' and not request: data_type = 'string' result = OrderedDict(type=data_type) # Retrieve Field metadata max_val = getattr(self._field, 'max_value', None) min_val = getattr(self._field, 'min_value', None) max_length = getattr(self._field, 'max_length', None) default = self._get_default_value() description = getattr(self._field, 'help_text', '') if data_format: result['format'] = data_format if max_val is not None and data_type in ('integer', 'number'): result['minimum'] = min_val if max_val is not None and data_type in ('integer', 'number'): result['maximum'] = max_val if max_length is not None and data_type == 'string': result['maxLength'] = max_length if description: result['description'] = description if default is not None: result['default'] = default if field_type in ['multiple choice', 'choice']: if isinstance(self._field.choices, dict): result['enum'] = [k for k in self._field.choices] if all( isinstance(item, int) for item in result.get('enum', ['1'])): result['type'] = 'integer' return result
def test_security(self): expected_result = [OrderedDict([('basic_authentication', [])])] instance = TestBasicAuthView() introspector = BasicAuthenticationIntrospector(instance) self.assertEqual(expected_result, introspector.security)
def responses(self): """ Collects method responses :return: swagger responses object :rtype: OrderedDict """ responses = OrderedDict() responses.update(self.introspector.responses) responses.update(super(BaseMethodIntrospector, self).responses) serializer = self._get_serializer() if serializer and not responses.get(200, None): si = SerializerIntrospector(serializer) if 'list' in self.method.lower(): pagination_introspector = get_pagination_introspector( self.view, si=si) responses.update(pagination_introspector.responses) else: response = OrderedDict([ ('description', 'Default response'), ('schema', si.build_response_object()['schema']), ]) responses[200] = response status_code = self.STATUS_CODES.get(self.method, self.DEFAULT_STATUS_CODE) response = responses.pop(200, None) # TODO this code wants to be rewritten if response: if status_code == status.HTTP_204_NO_CONTENT: response.pop('schema', None) if not responses.get(status_code, None): responses[status_code] = response if status_code not in responses: response = OrderedDict([ ('description', 'Empty response'), ]) responses[status_code] = response return responses