Пример #1
0
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()
Пример #2
0
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()
Пример #3
0
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
Пример #4
0
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
Пример #5
0
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
Пример #6
0
 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
Пример #7
0
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()
Пример #8
0
    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
Пример #9
0
    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
Пример #10
0
 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
Пример #11
0
    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
Пример #12
0
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
Пример #13
0
 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
Пример #14
0
    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()
Пример #15
0
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
Пример #16
0
 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
Пример #17
0
    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()
Пример #18
0
    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 == {}
Пример #19
0
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
Пример #20
0
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
Пример #21
0
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()
Пример #22
0
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
Пример #23
0
    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 == {}
Пример #24
0
    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 == {}
Пример #25
0
        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)
Пример #26
0
    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
Пример #28
0
 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
Пример #29
0
 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
Пример #30
0
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)
Пример #31
0
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)