python-openapi/openapi-core

[Bug]: No casting applied if type is object

jonathanberthias opened this issue · 0 comments

Actual Behavior

When validating a request, I get a different validation error depending on the structure of the schema.

If I have the following schema:

Pet:
  type: object  # <-- this causes the difference
  properties:
    id:
      type: integer
Pet2:
  allOf:
    - properties:
        id:
          type: integer

and send a request with body {"id": "hello"},

with the first schema I get:

openapi_core.casting.schemas.exceptions.CastError: Failed to cast value to integer type: hello

whereas in the second one I get:

openapi_core.validation.schemas.exceptions.InvalidSchemaValue: Value {'id': 'hello'} not valid for schema of type any: (<ValidationError: "'hello' is not of type 'integer'">,)

Expected Behavior

These schemas are equivalent, and as such I expected to get the same error. Specifically, I expected the validation error in both cases rather than the casting error as I asked for request validation.
Also, removing the type: object in the first schema seems to bypass casting entirely and leads to the same validation error as the second schema.

Steps to Reproduce

schema.yaml
openapi: "3.0.0"
info:
  title: "Sample API"
  version: "1.0.0"
servers:
  - url: /
paths:
  /pets:
    post:
      summary: Create a pet
      operationId: createPet
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Pet"
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Pet"
  /pets2:
    post:
      summary: Create a pet
      operationId: createPet2
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Pet2"
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Pet"
components:
  schemas:
    Pet:
      type: object  # <-- this causes the difference
      properties:
        id:
          type: integer
    Pet2:
      allOf:
        - properties:
            id:
              type: integer
import json
import traceback
import openapi_core
from openapi_core.contrib.starlette import StarletteOpenAPIRequest
from starlette.requests import Request


def starlette_request(path: str):
    return Request({
        "type": "http",
        "method": "POST",
        "path": path,
        "headers": [(b"content-type", b"application/json")],
        "query_string": "",
    })


body = json.dumps({"id": "hello"})

openapi = openapi_core.OpenAPI.from_file_path("schema.yaml")
try:
    openapi.validate_request(
        StarletteOpenAPIRequest(starlette_request("/pets"), body=body)
    )
except openapi_core.exceptions.OpenAPIError:
    traceback.print_exc()

try:
    openapi.validate_request(
        StarletteOpenAPIRequest(starlette_request("/pets2"), body=body)
    )
except openapi_core.exceptions.OpenAPIError:
    traceback.print_exc()

OpenAPI Core Version

0.19.0

OpenAPI Core Integration

starlette

Affected Area(s)

casting, validation

References

No response

Anything else we need to know?

No response

Would you like to implement a fix?

None