openapi-core icon indicating copy to clipboard operation
openapi-core copied to clipboard

Creating a spec fails if schemas contain non-JSON-serializable objects

Open Dunedan opened this issue 5 years ago • 0 comments

Creating a spec fails if schemas in the spec dict contain non-JSON-serializable objects. That's for example the case when generating the spec dict from a deserialized OpenAPI template in YAML format and having dates in the schema as shown in the example below:

#!/usr/bin/env python3

from openapi_core import create_spec
import yaml

template = """
openapi: "3.0.0"
info:
  title: Minimal valid OpenAPI specification
  version: "0.1"
paths:
  /status:
    get:
      parameters:
        - name: date
          in: query
          schema:
            type: string
            format: date
            example: 2020-06-23
      responses:
        default:
          description: Return the API status.
"""

spec_dict = yaml.safe_load(template)
create_spec(spec_dict)

Running this example code results in the following exception:

Traceback (most recent call last):
  File "./bar.py", line 27, in <module>
    create_spec(spec_dict)
  File "/home/user/.local/lib/python3.8/site-packages/openapi_core/schema/shortcuts.py", line 12, in create_spec
    return spec_factory.create(spec_dict, spec_url=spec_url)
  File "/home/user/.local/lib/python3.8/site-packages/openapi_core/schema/specs/factories.py", line 54, in create
    info, list(paths), servers=list(servers), components=components,
  File "/home/user/.local/lib/python3.8/site-packages/openapi_core/schema/paths/generators.py", line 38, in generate
    path_name, list(operations), parameters=list(parameters),
  File "/home/user/.local/lib/python3.8/site-packages/openapi_core/schema/operations/generators.py", line 68, in generate
    http_method, path_name, responses, list(parameters),
  File "/home/user/.local/lib/python3.8/site-packages/openapi_core/schema/parameters/generators.py", line 23, in generate_from_list
    parameter = self.parameter_factory.create(parameter_spec)
  File "/home/user/.local/lib/python3.8/site-packages/openapi_core/schema/parameters/factories.py", line 26, in create
    schema, _ = self.schemas_registry.get_or_create(schema_spec)
  File "/home/user/.local/lib/python3.8/site-packages/openapi_core/schema/schemas/registries.py", line 19, in get_or_create
    schema_hash = dicthash(schema_spec)
  File "/home/user/.local/lib/python3.8/site-packages/openapi_core/schema/schemas/util.py", line 15, in dicthash
    return hash(dumps(d, sort_keys=True))
  File "/usr/lib/python3.8/json/__init__.py", line 234, in dumps
    return cls(
  File "/usr/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python3.8/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type date is not JSON serializable

It doesn't matter if PyYAML or ruamel.yaml is used, as both convert dates from the YAML files into date/datetime objects.

The reason this fails is because openapi-core tries to json.dumps schema dicts:https://github.com/p1c2u/openapi-core/blob/97b568dc5535f5acbe719eed540c8888984d4732/openapi_core/schema/schemas/util.py#L14-L15

As a workaround converting the date into a string in the YAML file by explicitly adding quotes (example: "2020-06-23") works, however if I'm reading the OpenAPI specification correctly the example field of parameter objects can be of any type (https://swagger.io/specification/#parameter-object), potentially also creating problems with other types of objects which aren't JSON-serializable.

Dunedan avatar Jun 23 '20 09:06 Dunedan