openapi-core
openapi-core copied to clipboard
[Bug]: Can’t validate numerical string as `type`: `integer`/`number`/`boolean` wrapped in `allOf`/`anyOf`/`oneOf`
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 (0838a84e7c23d9f0691e0e7d496550d12513476e)
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
Hi @andersk
thanks for the report. This one will require type finding in AnyCaster
implementation right after ObjectCaster
.
Unfortunately it's not so straightforward to make it work soon.
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.