def generate_parameters_validator(api_path, path_definition, parameters, context, **kwargs): """ Generates a validator function to validate. - request.path against the path parameters. - request.query against the query parameters. - request.headers against the header parameters. - TODO: request.body against the body parameters. - TODO: request.formData against any form data. """ validators = {} path_level_parameters = path_definition.get('parameters', []) operation_level_parameters = parameters all_parameters = merge_parameter_lists( path_level_parameters, operation_level_parameters, ) # PATH in_path_parameters = filter_parameters(all_parameters, in_=PATH) validators['path'] = generate_path_parameters_validator( api_path, in_path_parameters, context, ) # QUERY in_query_parameters = filter_parameters(all_parameters, in_=QUERY) validators['query'] = generate_query_parameters_validator(in_query_parameters, context) # HEADERS in_header_parameters = filter_parameters(all_parameters, in_=HEADER) validators['headers'] = generate_header_validator(in_header_parameters, context) return functools.partial(validate_request_parameters, validators=validators)
def generate_path_validator(api_path, path_definition, parameters, context, **kwargs): """ Generates a callable for validating the parameters in a response object. """ path_level_parameters = dereference_parameter_list( path_definition.get('parameters', []), context, ) operation_level_parameters = dereference_parameter_list( parameters, context, ) all_parameters = merge_parameter_lists( path_level_parameters, operation_level_parameters, ) # PATH in_path_parameters = filter_parameters(all_parameters, in_=PATH) return chain_reduce_partial( attrgetter('path'), generate_path_parameters_validator(api_path, in_path_parameters, context), )
def validate(self, attrs): with ErrorCollection(inner=True) as errors: for api_path, path_definition in attrs.items(): path_parameter_names = set(get_parameter_names_from_path(api_path)) if path_definition is None: continue api_path_level_parameters = dereference_parameter_list( path_definition.get('parameters', []), parameter_definitions=self.context.get('parameters', {}), ) path_request_methods = set(REQUEST_METHODS).intersection( path_definition.keys(), ) if not path_request_methods: for parameter in api_path_level_parameters: if parameter['name'] not in path_parameter_names: errors[api_path].append( MESSAGES["path"]["missing_parameter"].format( parameter['name'], api_path, ), ) for method, operation_definition in path_definition.items(): if method not in REQUEST_METHODS: continue if operation_definition is None: operation_definition = {} operation_level_parameters = dereference_parameter_list( operation_definition.get('parameters', []), parameter_definitions=self.context.get('parameters', {}), ) parameters_in_path = filter_parameters( merge_parameter_lists( api_path_level_parameters, operation_level_parameters, ), in_=PATH, ) for parameter in parameters_in_path: if parameter['name'] not in path_parameter_names: key = "{method}:{api_path}".format( method=method.upper(), api_path=api_path, ) errors[key].append( MESSAGES["path"]["missing_parameter"].format( parameter['name'], api_path, ), ) return super(PathsSerializer, self).validate(attrs)
def test_filtering_parameters(lookup_kwargs, expected): parameters = parameters_validator([ ID_IN_PATH, USERNAME_IN_PATH, PAGE_IN_QUERY, PAGE_SIZE_IN_QUERY, ]) results = filter_parameters(parameters, **lookup_kwargs) assert len(results) == 1 for key in lookup_kwargs: assert results[0][key] == expected[key]
def test_find_parameter_errors_when_no_match_found(): parameters = parameters_validator([ ID_IN_PATH, USERNAME_IN_PATH, PAGE_IN_QUERY, PAGE_SIZE_IN_QUERY, ]) #sanity check assert not filter_parameters(parameters, name='not-in-parameters') with pytest.raises(ValueError): find_parameter(parameters, name='not-in-parameters')
def test_find_parameter_errors_when_multiple_found(): parameters = parameters_validator([ ID_IN_PATH, USERNAME_IN_PATH, PAGE_IN_QUERY, PAGE_SIZE_IN_QUERY, ]) #sanity check sanity = filter_parameters(parameters, in_=PATH) assert len(sanity) == 2 with pytest.raises(ValueError): find_parameter(parameters, in_=PATH)
def test_find_parameter_errors_when_no_match_found(): serializer = ParameterSerializer(many=True, data=[ ID_IN_PATH, USERNAME_IN_PATH, PAGE_IN_QUERY, PAGE_SIZE_IN_QUERY, ]) assert serializer.is_valid(), serializer.errors parameters = serializer.object #sanity check assert not filter_parameters(parameters, name='not-in-parameters') with pytest.raises(ValueError): find_parameter(parameters, name='not-in-parameters')
def test_filtering_parameters(lookup_kwargs, expected): serializer = ParameterSerializer(many=True, data=[ ID_IN_PATH, USERNAME_IN_PATH, PAGE_IN_QUERY, PAGE_SIZE_IN_QUERY, ]) assert serializer.is_valid(), serializer.errors parameters = serializer.object results = filter_parameters(parameters, **lookup_kwargs) assert len(results) == 1 for key in lookup_kwargs: assert results[0][key] == expected[key]
def test_find_parameter_errors_when_multiple_found(): serializer = ParameterSerializer(many=True, data=[ ID_IN_PATH, USERNAME_IN_PATH, PAGE_IN_QUERY, PAGE_SIZE_IN_QUERY, ]) assert serializer.is_valid(), serializer.errors parameters = serializer.object #sanity check sanity = filter_parameters(parameters, in_=PATH) assert len(sanity) == 2 with pytest.raises(ValueError): find_parameter(parameters, in_=PATH)
def test_merge_parameters_uses_last_write_wins(): duplicate_a = { 'name': 'duplicate', 'in': PATH, 'description': 'duplicate_a', 'type': INTEGER, 'required': True } duplicate_b = { 'name': 'duplicate', 'in': PATH, 'description': 'duplicate_b', 'type': STRING, 'required': True } main_serializer = ParameterSerializer(many=True, data=[ ID_IN_PATH, USERNAME_IN_PATH, duplicate_a, PAGE_IN_QUERY, ]) assert main_serializer.is_valid(), main_serializer.errors main_parameters = main_serializer.object sub_serializer = ParameterSerializer(many=True, data=[ duplicate_b, PAGE_SIZE_IN_QUERY, ]) assert sub_serializer.is_valid(), sub_serializer.errors sub_parameters = sub_serializer.object merged_parameters = merge_parameter_lists(main_parameters, sub_parameters) assert len(merged_parameters) == 5 assert find_parameter(merged_parameters, description='duplicate_b') assert not filter_parameters(merged_parameters, description='duplicate_a') assert find_parameter(merged_parameters, in_=PATH, name='id') assert find_parameter(merged_parameters, in_=PATH, name='username') assert find_parameter(merged_parameters, in_=QUERY, name='page') assert find_parameter(merged_parameters, in_=QUERY, name='page_size')
def test_merge_parameters_uses_last_write_wins(): duplicate_a = { 'name': 'duplicate', 'in': PATH, 'description': 'duplicate_a', 'type': INTEGER, 'required': True } duplicate_b = { 'name': 'duplicate', 'in': PATH, 'description': 'duplicate_b', 'type': STRING, 'required': True } main_parameters = parameters_validator([ ID_IN_PATH, USERNAME_IN_PATH, duplicate_a, PAGE_IN_QUERY, ]) sub_parameters = parameters_validator([ duplicate_b, PAGE_SIZE_IN_QUERY, ]) merged_parameters = merge_parameter_lists(main_parameters, sub_parameters) assert len(merged_parameters) == 5 assert find_parameter(merged_parameters, description='duplicate_b') assert not filter_parameters(merged_parameters, description='duplicate_a') assert find_parameter(merged_parameters, in_=PATH, name='id') assert find_parameter(merged_parameters, in_=PATH, name='username') assert find_parameter(merged_parameters, in_=QUERY, name='page') assert find_parameter(merged_parameters, in_=QUERY, name='page_size')
def generate_parameters_validator(api_path, path_definition, parameters, context, **kwargs): """ Generates a validator function to validate. - request.path against the path parameters. - request.query against the query parameters. - request.headers against the header parameters. - TODO: request.body against the body parameters. - TODO: request.formData against any form data. """ # TODO: figure out how to merge this with the same code in response # validation. validators = ValidationDict() path_level_parameters = dereference_parameter_list( path_definition.get('parameters', []), context, ) operation_level_parameters = dereference_parameter_list( parameters, context, ) all_parameters = merge_parameter_lists( path_level_parameters, operation_level_parameters, ) # PATH in_path_parameters = filter_parameters(all_parameters, in_=PATH) validators.add_validator( 'path', chain_reduce_partial( operator.attrgetter('path'), generate_path_parameters_validator(api_path, in_path_parameters, context), ), ) # QUERY in_query_parameters = filter_parameters(all_parameters, in_=QUERY) validators.add_validator( 'query', chain_reduce_partial( operator.attrgetter('query_data'), functools.partial( validate_query_parameters, query_parameters=in_query_parameters, context=context, ), ), ) # HEADERS in_header_parameters = filter_parameters(all_parameters, in_=HEADER) validators.add_validator( 'headers', chain_reduce_partial( operator.attrgetter('headers'), generate_header_validator(in_header_parameters, context), ), ) # FORM_DATA # in_form_data_parameters = filter_parameters(all_parameters, in_=FORM_DATA) # validators.add_validator( # 'form_data', # chain_reduce_partial( # operator.attrgetter('data'), # generate_form_data_validator(in_form_data_parameters, context), # ) # ) # REQUEST_BODY in_request_body_parameters = filter_parameters(all_parameters, in_=BODY) validators.add_validator( 'request_body', chain_reduce_partial( operator.attrgetter('data'), generate_request_body_validator(in_request_body_parameters, context), )) return generate_object_validator(field_validators=validators)
def generate_parameters_validator(api_path, path_definition, parameters, context, **kwargs): """ Generates a validator function to validate. - request.path against the path parameters. - request.query against the query parameters. - request.headers against the header parameters. - TODO: request.body against the body parameters. - TODO: request.formData against any form data. """ # TODO: figure out how to merge this with the same code in response # validation. validators = ValidationDict() path_level_parameters = dereference_parameter_list( path_definition.get('parameters', []), context, ) operation_level_parameters = dereference_parameter_list( parameters, context, ) all_parameters = merge_parameter_lists( path_level_parameters, operation_level_parameters, ) # PATH in_path_parameters = filter_parameters(all_parameters, in_=PATH) validators.add_validator( 'path', chain_reduce_partial( attrgetter('path'), generate_path_parameters_validator(api_path, in_path_parameters, context), ), ) # QUERY in_query_parameters = filter_parameters(all_parameters, in_=QUERY) validators.add_validator( 'query', chain_reduce_partial( attrgetter('query_data'), functools.partial( validate_query_parameters, query_parameters=in_query_parameters, context=context, ), ), ) # HEADERS in_header_parameters = filter_parameters(all_parameters, in_=HEADER) validators.add_validator( 'headers', chain_reduce_partial( attrgetter('headers'), generate_header_validator(in_header_parameters, context), ), ) # FORM_DATA # in_form_data_parameters = filter_parameters(all_parameters, in_=FORM_DATA) # validators.add_validator( # 'form_data', # chain_reduce_partial( # attrgetter('data'), # generate_form_data_validator(in_form_data_parameters, context), # ) # ) # REQUEST_BODY in_request_body_parameters = filter_parameters(all_parameters, in_=BODY) validators.add_validator( 'request_body', chain_reduce_partial( attrgetter('data'), generate_request_body_validator(in_request_body_parameters, context), ) ) return generate_object_validator(field_validators=validators)