Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Can’t validate numerical string as type: integer/number/boolean wrapped in allOf/anyOf/oneOf #698

Open
andersk opened this issue Oct 21, 2023 · 3 comments
Labels
kind/bug Indicates an issue

Comments

@andersk
Copy link
Contributor

andersk commented Oct 21, 2023

Actual Behavior

The string 123 from a path or query parameter validates as {"type": "integer"}, but unexpectedly fails to validate as {"allOf": [{"type": "integer"}]}. The same problem occurs with number or boolean in place of integer, or anyOf or oneOf in place of allOf.

(My actual use case involves {"oneOf": [{"type": "string", "enum": ["newest", "oldest", "first_unread"]}, {"type": "integer"}]}.)

Traceback (most recent call last):
  File "/home/anders/python/openapi-core/openapi_core/validation/decorators.py", line 31, in wrapper
    return f(*args, **kwds)
  File "/home/anders/python/openapi-core/openapi_core/validation/request/validators.py", line 200, in _get_parameter
    value, _ = self._get_param_or_header_and_schema(param, location)
  File "/home/anders/python/openapi-core/openapi_core/validation/validators.py", line 166, in _get_param_or_header_and_schema
    self._validate_schema(schema, casted)
  File "/home/anders/python/openapi-core/openapi_core/validation/validators.py", line 144, in _validate_schema
    validator.validate(value)
  File "/home/anders/python/openapi-core/openapi_core/validation/schemas/validators.py", line 36, in validate
    raise InvalidSchemaValue(value, schema_type, schema_errors=errors)
openapi_core.validation.schemas.exceptions.InvalidSchemaValue: Value 123 not valid for schema of type any: (<ValidationError: "'123' is not of type 'integer'">,)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/anders/python/openapi-core/test.py", line 41, in <module>
    validate_request(request, spec=spec)  # error
  File "/home/anders/python/openapi-core/openapi_core/shortcuts.py", line 321, in validate_request
    validate_apicall_request(
  File "/home/anders/python/openapi-core/openapi_core/shortcuts.py", line 396, in validate_apicall_request
    return v.validate(request)
  File "/home/anders/python/openapi-core/openapi_core/validation/request/validators.py", line 279, in validate
    raise err
  File "/home/anders/python/openapi-core/openapi_core/validation/request/validators.py", line 164, in _get_parameters
    value = self._get_parameter(parameters, param)
  File "/home/anders/python/openapi-core/openapi_core/validation/decorators.py", line 33, in wrapper
    self._raise_error(exc, self.err_validate_cls, f, *args, **kwds)
  File "/home/anders/python/openapi-core/openapi_core/validation/decorators.py", line 58, in _raise_error
    raise init(**kw) from exc
openapi_core.validation.request.exceptions.InvalidParameter: Invalid path parameter: bar_id

Expected Behavior

No error. A string that validates as {"type": "integer"} should also validate as {"allOf": [{"type": "integer"}]}.

Steps to Reproduce

from openapi_core import Spec, validate_request
from openapi_core.testing import MockRequest

spec = Spec.from_dict(
    {
        "openapi": "3.1.0",
        "info": {"title": "test", "version": "0"},
        "paths": {
            "/foo/{foo_id}": {
                "get": {
                    "parameters": [
                        {
                            "name": "foo_id",
                            "in": "path",
                            "required": True,
                            "schema": {"type": "integer"},
                        },
                    ],
                },
            },
            "/bar/{bar_id}": {
                "get": {
                    "parameters": [
                        {
                            "name": "bar_id",
                            "in": "path",
                            "required": True,
                            "schema": {"allOf": [{"type": "integer"}]},
                        },
                    ],
                },
            },
        },
    }
)

request = MockRequest("http://localhost", "get", "/foo/123")
validate_request(request, spec=spec)  # ok

request = MockRequest("http://localhost", "get", "/bar/123")
validate_request(request, spec=spec)  # error

OpenAPI Core Version

0.18.1 or current Git (0838a84)

OpenAPI Core Integration

none

Affected Area(s)

No response

References

No response

Anything else we need to know?

No response

Would you like to implement a fix?

None

@andersk andersk added the kind/bug Indicates an issue label Oct 21, 2023
@p1c2u p1c2u mentioned this issue Oct 22, 2023
@p1c2u
Copy link
Collaborator

p1c2u commented Oct 22, 2023

Hi @andersk

thanks for the report. This one will require type finding in AnyCaster implementation right after ObjectCaster.

@p1c2u
Copy link
Collaborator

p1c2u commented Oct 31, 2023

Unfortunately it's not so straightforward to make it work soon.

@andersk
Copy link
Contributor Author

andersk commented Nov 6, 2023

Hmm, I can see why this would be difficult. There are some questions here that the specification doesn’t seem to address; for example, if a path or query value 123 validates as both {"type": "integer"} (with casting) and {"type": "string"} (without casting), should it also validate as {"allOf": [{"type": "integer"}, {"type": "string"}]}, even though one would expect that to be self-contradictory in the ordinary JSON schema sense? I’m not sure what the right answer is.

Do you happen to know what part of the specification allows a path or query value 123 to validate as {"type": "integer"} in the first place? It’s certainly convenient and what I’d expect without trying to lawyer too hard, but I haven’t found a justification for it in the specification.

andersk added a commit to andersk/zulip that referenced this issue Feb 1, 2024
Real requests would not validate against the previous version.  There
seems to be no consistent way to determine whether a string parameter
should be coerced to an integer for validation against an allOf
schema (which works at the level of JSON objects, not strings).

See also python-openapi/openapi-core#698.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
andersk added a commit to andersk/zulip that referenced this issue Feb 2, 2024
Real requests would not validate against the previous version.  There
seems to be no consistent way to determine whether a string parameter
should be coerced to an integer for validation against an allOf
schema (which works at the level of JSON objects, not strings).

See also python-openapi/openapi-core#698.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
andersk added a commit to andersk/zulip that referenced this issue Feb 2, 2024
Real requests would not validate against the previous version.  There
seems to be no consistent way to determine whether a string parameter
should be coerced to an integer for validation against an allOf
schema (which works at the level of JSON objects, not strings).

See also python-openapi/openapi-core#698.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
andersk added a commit to zulip/zulip that referenced this issue Feb 6, 2024
Real requests would not validate against the previous version.  There
seems to be no consistent way to determine whether a string parameter
should be coerced to an integer for validation against an allOf
schema (which works at the level of JSON objects, not strings).

See also python-openapi/openapi-core#698.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
amaranand360 pushed a commit to amaranand360/zulip that referenced this issue Feb 17, 2024
Real requests would not validate against the previous version.  There
seems to be no consistent way to determine whether a string parameter
should be coerced to an integer for validation against an allOf
schema (which works at the level of JSON objects, not strings).

See also python-openapi/openapi-core#698.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
mananbordia pushed a commit to mananbordia/zulip that referenced this issue Feb 27, 2024
Real requests would not validate against the previous version.  There
seems to be no consistent way to determine whether a string parameter
should be coerced to an integer for validation against an allOf
schema (which works at the level of JSON objects, not strings).

See also python-openapi/openapi-core#698.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
andersk added a commit to andersk/zulip that referenced this issue Mar 7, 2024
Real requests would not validate against the previous version.  There
seems to be no consistent way to determine whether a string parameter
should be coerced to an integer for validation against an allOf
schema (which works at the level of JSON objects, not strings).

See also python-openapi/openapi-core#698.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
(cherry picked from commit 0514f92)
timabbott pushed a commit to zulip/zulip that referenced this issue Mar 7, 2024
Real requests would not validate against the previous version.  There
seems to be no consistent way to determine whether a string parameter
should be coerced to an integer for validation against an allOf
schema (which works at the level of JSON objects, not strings).

See also python-openapi/openapi-core#698.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
(cherry picked from commit 0514f92)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Indicates an issue
Projects
None yet
Development

No branches or pull requests

2 participants