def validate_data(path, request, response, validate_request, validate_response): if response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED: return spec = _load_spec(resolve(path).kwargs.get('version')) request = DjangoOpenAPIRequestFactory.create(request) response = DjangoOpenAPIResponseFactory.create(response) # request if validate_request: validator = RequestValidator( spec, custom_formatters=CUSTOM_FORMATTERS) result = validator.validate(request) try: result.raise_for_errors() except OpenAPIMediaTypeError: if response.status_code != status.HTTP_400_BAD_REQUEST: raise except OpenAPIParameterError: # TODO(stephenfin): In API v2.0, this should be an error. As things # stand, we silently ignore these issues. assert response.status_code == status.HTTP_200_OK # response if validate_response: validator = ResponseValidator( spec, custom_formatters=CUSTOM_FORMATTERS) result = validator.validate(request, response) result.raise_for_errors()
def validate_request(response): """Validate an API request""" openapi_spec = get_openapi_spec() validator = RequestValidator(openapi_spec) request = wrap_request(response.request, openapi_spec) result = validator.validate(request) print(result.errors) result.raise_for_errors() validator = ResponseValidator(openapi_spec) response = wrap_response(response) result = validator.validate(request, response) print(result.errors) result.raise_for_errors()
def sent_request(client14, container): path = container['request_data']['path'] resp = client14.simulate_get('{}/spec/1.4'.format(path)) assert HTTP_OK == resp.status spec = create_spec(resp.json) req = FalconOpenAPIWrapper(app, **container['request_data']) validator = RequestValidator(spec) result = validator.validate(req) assert not result.errors validator = ResponseValidator(spec) result = validator.validate(req, req) assert not result.errors container['response'] = req.request
def create_and_validate_request(endpoint, method, payload='', params=[], headers=[]): """ Helper function to create OpenAPIRequest and validate it :param endpoint: API endpoint :param method: API request method :param payload: API request payload :param params: API request payload :param headers: API request headers :return: - request: OpenAPIRequest - request_result: result of request validation """ parameters = RequestParameters(query=ImmutableMultiDict(params), path=endpoint, header=headers) request = OpenAPIRequest( full_url_pattern=endpoint, method=method, parameters=parameters, body=payload, mimetype='application/json', ) validator = RequestValidator(spec) request_result = validator.validate(request) return request, request_result
def sent_request(client14, container, spec_url='/spec/1.4'): version = container['request_data']['headers'].get( 'X-API-VERSION') or '1.4' resp = client14.simulate_get('/spec/{}'.format(version)) assert HTTP_OK == resp.status spec = create_spec(resp.json) req = FalconOpenAPIWrapper(app, **container['request_data']) validator = RequestValidator(spec) result = validator.validate(req) assert not result.errors validator = ResponseValidator(spec) result = validator.validate(req, req) assert not result.errors container['response'] = req.request
def test_request_validator_with_query(self, spec, request_factory): validator = RequestValidator(spec) request = request_factory('GET', '/browse/12', query_string='detail_level=2', subdomain='kb') openapi_request = FalconOpenAPIRequestFactory.create(request) result = validator.validate(openapi_request) assert not result.errors
def validate_request(response): """Validate an API request""" path = (Path(here) / '../jupyterlab_server/rest-api.yml').resolve() yaml = YAML(typ='safe') spec_dict = yaml.load(path.read_text(encoding='utf-8')) spec = create_spec(spec_dict) validator = RequestValidator(spec) request = wrap_request(response.request, spec) result = validator.validate(request) print(result.errors) result.raise_for_errors() validator = ResponseValidator(spec) response = wrap_response(response) result = validator.validate(request, response) print(result.errors) result.raise_for_errors()
def test_hosts(self, factory, server, spec_path): spec_dict = factory.spec_from_file(spec_path) spec = create_spec(spec_dict) validator = RequestValidator(spec) request = MockRequest(server, "get", "/status") result = validator.validate(request) assert not result.errors
def validate(*args, **kwargs): if ENABLE_OPENAPI_VALIDATION: spec = get_openapi_spec() openapi_request = FlaskOpenAPIRequest(request) validator = RequestValidator(spec) result = validator.validate(openapi_request) result.raise_for_errors() response = function(*args, **kwargs) if ENABLE_OPENAPI_VALIDATION: openapi_response = FlaskOpenAPIResponse(response) validator = ResponseValidator(spec) result = validator.validate(openapi_request, openapi_response) result.raise_for_errors() return response
def test_request_validator_path_pattern(self, django_spec, request_factory): from django.urls import resolve validator = RequestValidator(django_spec) request = request_factory.get('/admin/auth/group/1/') request.resolver_match = resolve('/admin/auth/group/1/') openapi_request = DjangoOpenAPIRequest(request) result = validator.validate(openapi_request) assert not result.errors
def test_post_object_failure(self, factory, response, spec_path): spec_dict = factory.spec_from_file(spec_path) spec = create_spec(spec_dict) validator = RequestValidator(spec) request = MockRequest("http://www.example.com", "post", "/object", data=json.dumps(response)) result = validator.validate(request) assert result.errors
async def validate_request(request: web.Request, spec: OpenApiSpec): """ Validates aiohttp.web.Request against an opeapi specification Returns parameters dict, body object and list of errors (exceptions objects) """ req = await AiohttpOpenAPIRequest.create(request) validator = RequestValidator(spec) result = validator.validate(req) return result.parameters, result.body, result.errors
def test_request_validator_path_pattern(self, spec): validator = RequestValidator(spec) request = requests.Request( 'POST', 'http://localhost/browse/12/', params={'q': 'string'}, headers={'content-type': 'application/json'}, json={'param1': 1}, ) openapi_request = RequestsOpenAPIRequest(request) result = validator.validate(openapi_request) assert not result.errors
def test_invalid_path(self, factory, server, spec_path): spec_dict = factory.spec_from_file(spec_path) spec = Spec.create(spec_dict) validator = RequestValidator(spec) request = MockRequest(server, "get", "/nonexistent") result = validator.validate(request) assert len(result.errors) == 1 assert isinstance(result.errors[0], PathNotFound) assert result.body is None assert result.parameters == Parameters()
class OpenApiValidator: """ Used to validate data in the request->response cycle against openapi specs """ @classmethod def create(cls, app: web.Application, _version=""): specs = get_specs(app) # TODO: one per version! return cls(specs) def __init__(self, spec: OpenApiSpec): self._reqvtor = RequestValidator(spec, custom_formatters=None) self._resvtor = ResponseValidator(spec, custom_formatters=None) # Current self.current_request = None # wrapper request async def check_request(self, request: web.Request): self.current_request = None rq = await AiohttpOpenAPIRequest.create(request) result = self._reqvtor.validate(rq) # keeps current request and reuses in response self.current_request = rq if result.errors: err = create_error_response( result.errors, "Failed request validation against API specs", web.HTTPBadRequest, ) raise err path, query = [result.parameters[k] for k in (PATH_KEY, QUERY_KEY)] return path, query, result.body def check_response(self, response: web.Response): req = self.current_request res = AiohttpOpenAPIResponse( response, response.text ) # FIXME:ONLY IN SERVER side. Async in client! result = self._resvtor.validate(req, res) if result.errors: err = create_error_response( result.errors, "Failed response validation against API specs", web.HTTPServiceUnavailable, ) raise err
def test_request_validator_path_pattern(self, spec): validator = RequestValidator(spec) request = requests.Request( "POST", "http://localhost/browse/12/", params={"q": "string"}, headers={"content-type": "application/json"}, json={"param1": 1}, ) openapi_request = RequestsOpenAPIRequest(request) result = validator.validate(openapi_request) assert not result.errors
def test_invalid_operation(self, factory, server, spec_path): spec_dict = factory.spec_from_file(spec_path) spec = create_spec(spec_dict) validator = RequestValidator(spec) request = MockRequest(server, "post", "/status") result = validator.validate(request) assert len(result.errors) == 1 assert isinstance(result.errors[0], OperationNotFound) assert result.body is None assert result.parameters == RequestParameters()
def test_invalid_operation(self, factory, server, spec_path): spec_dict = factory.spec_from_file(spec_path) spec = create_spec(spec_dict) validator = RequestValidator(spec) request = MockRequest(server, "get", "/nonexistent") result = validator.validate(request) assert len(result.errors) == 1 assert isinstance(result.errors[0], InvalidOperation) assert result.body is None assert result.parameters == {}
def validate_body(spec, request, wrapper_class=None): if wrapper_class is not None: request = wrapper_class(request) validator = RequestValidator(spec) result = validator.validate(request) try: result.raise_for_errors() except OpenAPIParameterError: return result.body else: return result.body
def validate_body(spec, request, request_factory=None): if request_factory is not None: request = request_factory(request) validator = RequestValidator(spec) result = validator.validate(request) try: result.raise_for_errors() except OpenAPIParameterError: return result.body else: return result.body
def validate_data(path, request, response): if response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED: return spec = _load_spec(resolve(path).kwargs.get('version')) request = DRFOpenAPIRequest(request) response = DRFOpenAPIResponse(response) # request validator = RequestValidator(spec, custom_formatters=CUSTOM_FORMATTERS) result = validator.validate(request) try: result.raise_for_errors() except OpenAPIMediaTypeError: assert response.status_code == status.HTTP_400_BAD_REQUEST except OpenAPIParameterError: # TODO(stephenfin): In API v2.0, this should be an error. As things # stand, we silently ignore these issues. assert response.status_code == status.HTTP_200_OK # response validator = ResponseValidator(spec, custom_formatters=CUSTOM_FORMATTERS) result = validator.validate(request, response) result.raise_for_errors()
def validate_parameters(spec, request, request_factory=None): if request_factory is not None: request = request_factory(request) validator = RequestValidator(spec) result = validator.validate(request) try: result.raise_for_errors() except ( OpenAPIRequestBodyError, OpenAPIMediaTypeError, OpenAPISchemaError, ): return result.parameters else: return result.parameters
def test_request_override_param(self, spec_dict): # override path parameter on operation spec_dict["paths"]["/resource"]["get"]["parameters"] = [{ # full valid parameter object required "name": "resId", "in": "query", "required": False, "schema": { "type": "integer", }, }] validator = RequestValidator(create_spec(spec_dict)) request = MockRequest('http://example.com', 'get', '/resource') result = validator.validate(request) assert len(result.errors) == 0 assert result.body is None assert result.parameters == {}
def test_request_override_param_uniqueness(self, spec_dict): # add parameter on operation with same name as on path but # different location spec_dict["paths"]["/resource"]["get"]["parameters"] = [{ # full valid parameter object required "name": "resId", "in": "header", "required": False, "schema": { "type": "integer", }, }] validator = RequestValidator(create_spec(spec_dict)) request = MockRequest('http://example.com', 'get', '/resource') result = validator.validate(request) assert len(result.errors) == 1 assert type(result.errors[0]) == MissingRequiredParameter assert result.body is None assert result.parameters == {}
def wrapper_validate(*args, **kwargs): try: data = request.get_json() except BadRequest: result = "The request body is not a well-formed JSON." log.debug("create_circuit result %s %s", result, 400) raise BadRequest(result) from BadRequest if data is None: result = "The request body mimetype is not application/json." log.debug("update result %s %s", result, 415) raise UnsupportedMediaType(result) validator = RequestValidator(spec) openapi_request = FlaskOpenAPIRequest(request) result = validator.validate(openapi_request) if result.errors: errors = result.errors[0] if hasattr(errors, "schema_errors"): schema_errors = errors.schema_errors[0] error_log = { "error_message": schema_errors.message, "error_validator": schema_errors.validator, "error_validator_value": schema_errors.validator_value, "error_path": list(schema_errors.path), "error_schema": schema_errors.schema, "error_schema_path": list(schema_errors.schema_path), } log.debug("error response: %s", error_log) error_response = f"{schema_errors.message} for field" error_response += ( f" {'/'.join(map(str,schema_errors.path))}." ) else: error_response = ( "The request body mimetype is not application/json." ) raise BadRequest(error_response) from BadRequest return func(*args, data=data, **kwargs)
def get(self, request, pk=None): with open(settings.OPENAPI_SPEC_PATH) as file: spec_yaml = file.read() spec_dict = yaml.safe_load(spec_yaml) spec = create_spec(spec_dict) openapi_request = DjangoOpenAPIRequest(request) request_validator = RequestValidator(spec) result = request_validator.validate(openapi_request) result.raise_for_errors() response_dict = { "test": "test_val", } django_response = JsonResponse(response_dict) django_response['X-Rate-Limit'] = '12' openapi_response = DjangoOpenAPIResponse(django_response) validator = ResponseValidator(spec) result = validator.validate(openapi_request, openapi_response) result.raise_for_errors() return django_response
def test_request_validator_path_pattern(self, spec): validator = RequestValidator(spec) request = requests.Request('GET', 'http://localhost/browse/12/') openapi_request = RequestsOpenAPIRequest(request) result = validator.validate(openapi_request) assert not result.errors
def test_request_validator_path_pattern(self, spec, request_factory): validator = RequestValidator(spec) request = request_factory('GET', '/browse/12', subdomain='kb') openapi_request = FalconOpenAPIRequestFactory.create(request) result = validator.validate(openapi_request) assert not result.errors
def test_request_validator_path_pattern(self, flask_spec, request_factory): validator = RequestValidator(flask_spec) request = request_factory("GET", "/browse/12/", subdomain="kb") openapi_request = FlaskOpenAPIRequest(request) result = validator.validate(openapi_request) assert not result.errors
def test_tabular_data_api14(buzzfeed_fakenews_resource, client14): _rid = buzzfeed_fakenews_resource.id resp = client14.simulate_get('/resources/{}/data/spec/1.4'.format(_rid)) assert HTTP_OK == resp.status spec = create_spec(resp.json) # Test tablular data format req = FalconOpenAPIWrapper( app, method='GET', path='/resources/{}/data'.format(_rid), headers={ 'X-API-VERSION': '1.4', 'Accept-Language': 'pl' }, ) validator = RequestValidator(spec) result = validator.validate(req) assert not result.errors validator = ResponseValidator(spec) result = validator.validate(req, req) assert not result.errors resp = req.request assert HTTP_OK == resp.status valid, validated_data, errors = jsonapi_validator(resp.json) assert valid is True assert len(validated_data) == 20 assert validated_data[0]['type'] == 'row' assert validated_data[0]['resource']['id'] == str(_rid) data = resp.json['data'][1] assert data['type'] == 'row' assert data['id'] == 'd4ff4c97-5d9e-56a5-9d7c-46547879b7ae' assert data['meta']['row_no'] == 2 assert data['attributes']['col3'] == '2,290,000.00' assert data['relationships']['resource']['data']['id'] == str(_rid) assert resp.json['meta']['count'] == 1000 assert len(resp.json['meta']) == 9 assert len(resp.json['meta']['headers_map']) == 6 assert 'title' in resp.json['meta']['headers_map'] assert 'published_date' in resp.json['meta']['headers_map'] assert resp.json['meta']['headers_map']['published_date'] == 'col4' assert len(resp.json['meta']['data_schema']['fields']) == 6 links = resp.json['links'] assert len(links) == 3 assert links[ 'self'] == 'http://falconframework.org/resources/{}/data?page=1'.format( _rid) assert links[ 'last'] == 'http://falconframework.org/resources/{}/data?page=50'.format( _rid) assert links[ 'next'] == 'http://falconframework.org/resources/{}/data?page=2'.format( _rid) # Test search req = FalconOpenAPIWrapper(app, method='GET', path='/resources/{}/data'.format(_rid), query={ 'q': 'col5:Crime', 'per_page': 25 }, headers={ 'X-API-VERSION': '1.4', 'Accept-Language': 'pl' }) validator = RequestValidator(spec) result = validator.validate(req) assert not result.errors validator = ResponseValidator(spec) result = validator.validate(req, req) assert not result.errors resp = req.request assert HTTP_OK == resp.status valid, validated_data, errors = jsonapi_validator(resp.json) assert valid is True assert len(validated_data) == 21 meta = resp.json['meta'] assert meta['count'] == 21 links = resp.json['links'] assert len(links) == 1 assert links[ 'self'] == 'http://falconframework.org/resources/{}/data?per_page=25&q=col5%3ACrime&page=1'.format( _rid) req = FalconOpenAPIWrapper(app, method='GET', path='/resources/{}/data'.format(_rid), query={ 'q': 'col1:President AND col5:Norwegian', 'per_page': 5 }, headers={ 'X-API-VERSION': '1.4', 'Accept-Language': 'pl' }) validator = RequestValidator(spec) result = validator.validate(req) assert not result.errors validator = ResponseValidator(spec) result = validator.validate(req, req) assert not result.errors resp = req.request assert HTTP_OK == resp.status valid, validated_data, errors = jsonapi_validator(resp.json) assert valid is True assert len(validated_data) == 1 assert validated_data[0]['col3'] == '4347' assert validated_data[0]['col5'] == 'Norwegian Lawmakers' links = resp.json['links'] assert len(links) == 1 assert 'self' in links resp = client14.simulate_get( '/resources/{}/data'.format(_rid), query_string='q=col4:[2018-12-01 TO *]&per_page=10&page=3') assert HTTP_OK == resp.status valid, validated_data, errors = jsonapi_validator(resp.json) assert valid is True assert len(validated_data) == 10 meta = resp.json['meta'] assert meta['count'] == 61 links = resp.json['links'] assert len(links) == 5 assert links[ 'first'] == 'http://falconframework.org/resources/{}/' \ 'data?page=1&per_page=10&q=col4%3A%5B2018' \ '-12-01%20TO%20%2A%5D'.format(_rid) assert links[ 'next'] == 'http://falconframework.org/resources/{}/' \ 'data?page=4&per_page=10&q=col4%3A%5B2018' \ '-12-01%20TO%20%2A%5D'.format(_rid) assert links[ 'prev'] == 'http://falconframework.org/resources/{}/' \ 'data?page=2&per_page=10&q=col4%3A%5B2018' \ '-12-01%20TO%20%2A%5D'.format(_rid) assert links[ 'last'] == 'http://falconframework.org/resources/{}/' \ 'data?page=7&per_page=10&q=col4%3A%5B2018' \ '-12-01%20TO%20%2A%5D'.format(_rid) assert links[ 'self'] == 'http://falconframework.org/resources/{}/' \ 'data?page=3&per_page=10&q=col4%3A%5B2018' \ '-12-01%20TO%20%2A%5D'.format(_rid) # Test single row req = FalconOpenAPIWrapper( app, method='GET', path='/resources/{}/data/6b73a62e-7af2-531c-87ae-df51a74af23f'.format( _rid), path_params={'id': '6b73a62e-7af2-531c-87ae-df51a74af23f'}, path_pattern='/resources/%s/data/{id}' % _rid, headers={ 'X-API-VERSION': '1.4', 'Accept-Language': 'pl' }) validator = RequestValidator(spec) result = validator.validate(req) assert not result.errors validator = ResponseValidator(spec) result = validator.validate(req, req) assert not result.errors resp = req.request assert HTTP_OK == resp.status valid, validated_data, errors = jsonapi_validator(resp.json) assert valid is True assert len(validated_data) == 9 assert validated_data['col5'] == 'Norwegian Lawmakers' assert validated_data[ 'col1'] == 'President Trump Nominated for Nobel Peace Prize by ' \ 'Norwegian Lawmakers' assert validated_data['resource']['id'] == str(_rid) data = resp.json['data'] assert data['type'] == 'row' assert data['meta']['row_no'] == 774 assert data['relationships']['resource']['data']['id'] == str(_rid) meta = resp.json['meta'] assert len(meta) == 7 assert len(meta['headers_map']) == 6 assert 'title' in meta['headers_map'] assert 'published_date' in meta['headers_map'] assert meta['headers_map']['published_date'] == 'col4' assert len(meta['data_schema']['fields']) == 6 links = resp.json['links'] assert len(links) == 1 assert links[ 'self'] == 'http://falconframework.org/resources/{}/' \ 'data/6b73a62e-7af2-531c-87ae-df51a74af23f'.format(_rid)
def test_tabular_data_api14(buzzfeed_fakenews_resource, client14, mocker): _rid = buzzfeed_fakenews_resource.id resp = client14.simulate_get('/resources/{}/data/spec/1.4'.format(_rid)) assert HTTP_OK == resp.status spec = create_spec(resp.json) # Test tabular data format req = FalconOpenAPIWrapper( app, method='GET', path='/resources/{}/data'.format(_rid), headers={ 'X-API-VERSION': '1.4', 'Accept-Language': 'pl' }, ) validator = RequestValidator(spec) result = validator.validate(req) assert not result.errors validator = ResponseValidator(spec) result = validator.validate(req, req) assert not result.errors resp = req.request assert HTTP_OK == resp.status valid, validated_data, errors = jsonapi_validator(resp.json) assert valid is True assert len(validated_data) == 20 assert validated_data[0]['type'] == 'row' assert validated_data[0]['resource']['id'] == str(_rid) data = resp.json['data'][1] assert data['type'] == 'row' # assert data['id'] == 'b97a04f7-2549-590e-b9ac-821ed67342fd' # obsolete. assert data['id'] == 'a20713b6-2a0b-582e-b1c2-75a095bace86' assert data['meta']['row_no'] == 2 assert data['attributes']['col3']['val'] == '2,290,000.00' assert data['relationships']['resource']['data']['id'] == str(_rid) assert resp.json['meta']['count'] == 1000 assert len(resp.json['meta']) == 9 assert len(resp.json['meta']['headers_map']) == 6 assert 'title' in resp.json['meta']['headers_map'].values() assert 'published_date' in resp.json['meta']['headers_map'].values() assert resp.json['meta']['headers_map']['col4'] == 'published_date' assert len(resp.json['meta']['data_schema']['fields']) == 6 links = resp.json['links'] assert len(links) == 3 assert links[ 'self'] == 'http://api.test.mcod/resources/{}/data?page=1'.format(_rid) assert links[ 'last'] == 'http://api.test.mcod/resources/{}/data?page=50'.format( _rid) assert links[ 'next'] == 'http://api.test.mcod/resources/{}/data?page=2'.format(_rid) # Test search req = FalconOpenAPIWrapper(app, method='GET', path='/resources/{}/data'.format(_rid), query={ 'q': 'col5:Crime', 'per_page': 25 }, headers={ 'X-API-VERSION': '1.4', 'Accept-Language': 'pl' }) validator = RequestValidator(spec) result = validator.validate(req) assert not result.errors validator = ResponseValidator(spec) result = validator.validate(req, req) assert not result.errors resp = req.request assert HTTP_OK == resp.status valid, validated_data, errors = jsonapi_validator(resp.json) assert valid is True assert len(validated_data) == 21 meta = resp.json['meta'] assert meta['count'] == 21 links = resp.json['links'] assert len(links) == 1 assert links[ 'self'] == 'http://api.test.mcod/resources/{}/data?per_page=25&q=col5%3ACrime&page=1'.format( _rid) req = FalconOpenAPIWrapper(app, method='GET', path='/resources/{}/data'.format(_rid), query={ 'q': 'col1:President AND col5:Norwegian', 'per_page': 5 }, headers={ 'X-API-VERSION': '1.4', 'Accept-Language': 'pl' }) validator = RequestValidator(spec) result = validator.validate(req) assert not result.errors validator = ResponseValidator(spec) result = validator.validate(req, req) assert not result.errors resp = req.request assert HTTP_OK == resp.status valid, validated_data, errors = jsonapi_validator(resp.json) assert valid is True assert len(validated_data) == 1 assert validated_data[0]['col3']['val'] == '4347' assert validated_data[0]['col5']['val'] == 'Norwegian Lawmakers' links = resp.json['links'] assert len(links) == 1 assert 'self' in links resp = client14.simulate_get( '/resources/{}/data'.format(_rid), query_string='q=col4.date:[2018-12-01 TO *]&per_page=10&page=2') assert HTTP_OK == resp.status valid, validated_data, errors = jsonapi_validator(resp.json) assert valid is True assert len(validated_data) == 10 meta = resp.json['meta'] assert meta['count'] == 61 links = resp.json['links'] assert len(links) == 5 assert links[ 'first'] == 'http://api.test.mcod/resources/{}/' \ 'data?page=1&per_page=10&q=col4.date%3A%5B2018' \ '-12-01%20TO%20%2A%5D'.format(_rid) assert links[ 'next'] == 'http://api.test.mcod/resources/{}/' \ 'data?page=3&per_page=10&q=col4.date%3A%5B2018' \ '-12-01%20TO%20%2A%5D'.format(_rid) assert links[ 'prev'] == 'http://api.test.mcod/resources/{}/' \ 'data?page=1&per_page=10&q=col4.date%3A%5B2018' \ '-12-01%20TO%20%2A%5D'.format(_rid) assert links[ 'last'] == 'http://api.test.mcod/resources/{}/' \ 'data?page=7&per_page=10&q=col4.date%3A%5B2018' \ '-12-01%20TO%20%2A%5D'.format(_rid) assert links[ 'self'] == 'http://api.test.mcod/resources/{}/' \ 'data?page=2&per_page=10&q=col4.date%3A%5B2018' \ '-12-01%20TO%20%2A%5D'.format(_rid) row_id = validated_data[0]['id'] # Test single row req = FalconOpenAPIWrapper(app, method='GET', path='/resources/{}/data/{}'.format( _rid, row_id), path_params={'id': row_id}, path_pattern='/resources/%s/data/{id}' % _rid, headers={ 'X-API-VERSION': '1.4', 'Accept-Language': 'pl' }) validator = RequestValidator(spec) result = validator.validate(req) assert not result.errors validator = ResponseValidator(spec) result = validator.validate(req, req) assert not result.errors resp = req.request assert HTTP_OK == resp.status valid, validated_data, errors = jsonapi_validator(resp.json) assert valid is True assert len(validated_data) == 10 assert validated_data['col1'][ 'val'] == 'Mums across Britain preparing to strum one off over CBeebies Bedtime Story tonight' assert validated_data['resource']['id'] == str(_rid) data = resp.json['data'] assert data['type'] == 'row' assert data['meta']['row_no'] == 357 assert data['relationships']['resource']['data']['id'] == str(_rid) meta = resp.json['meta'] assert len(meta) == 7 assert len(meta['headers_map']) == 6 assert 'title' in meta['headers_map'].values() assert 'published_date' in meta['headers_map'].values() assert meta['headers_map']['col4'] == 'published_date' assert len(meta['data_schema']['fields']) == 6 links = resp.json['links'] assert len(links) == 1 assert links[ 'self'] == 'http://api.test.mcod/resources/{}/' \ 'data/{}'.format(_rid, row_id)