python-openapi / openapi-spec-validator

OpenAPI Spec Validator is a CLI, pre-commit hook and python package that validates OpenAPI Specs against the OpenAPI 2.0 (aka Swagger), OpenAPI 3.0 and OpenAPI 3.1 specification.
Apache License 2.0
329 stars 61 forks source link

writeOnly with default doesn't work in 0.6.0 #253

Closed zzzevaka closed 9 months ago

zzzevaka commented 1 year ago

Good day! I use OpenAPI 3.0.0 schema and it stopped working with properties that have writeOnly and default at the same time.

A simple code snippet:

import json
from openapi_spec_validator import validate_spec

data = json.loads('''{
  "openapi": "3.0.0",
  "info": {
    "version": "1.0.0",
    "title": ""
  },
  "servers": [],
  "paths": {
    "/pets": {
      "post": {
        "summary": "Create a pet",
        "tags": [],
        "responses": {
          "201": {
            "description": "Null response"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Pet": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "readOnly": true
          },
          "write_only": {
            "type": "string",
            "writeOnly": true,
            "default": "hello"
          }
        }
      }
    }
  }
}''')

validate_spec(data)

The error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.10/site-packages/openapi_spec_validator/shortcuts.py", line 19, in validate_spec
    return validator.validate(spec, base_uri=base_uri, spec_url=spec_url)
  File "/usr/local/lib/python3.10/site-packages/openapi_spec_validator/validation/proxies.py", line 34, in validate
    raise err
openapi_spec_validator.validation.exceptions.OpenAPIValidationError: Tried to read write-only property with hello

Failed validating 'writeOnly' in schema:
    {'default': 'hello', 'type': 'string', 'writeOnly': True}

On instance:
    'hello'

As I understood the root cause is here https://github.com/python-openapi/openapi-schema-validator/pull/85

As a workaround, I made a custom validator that uses OAS30WriteValidator:

from functools import partial
from jsonschema.validators import Draft4Validator
from openapi_spec_validator.schemas import schema_v30
from lazy_object_proxy import Proxy
from openapi_spec_validator.validation.validators import SpecValidator
from openapi_schema_validator import oas30_format_checker
from jsonschema_spec.handlers import default_handlers
from openapi_schema_validator.validators import OAS30WriteValidator

get_openapi_v30_schema_validator = partial(Draft4Validator, schema_v30)
openapi_v30_schema_validator = Proxy(get_openapi_v30_schema_validator)
get_openapi_v30_spec_validator = partial(
    SpecValidator,
    openapi_v30_schema_validator,
    OAS30WriteValidator,
    oas30_format_checker,
    resolver_handlers=default_handlers,
)
openapi_v30_spec_validator = Proxy(get_openapi_v30_spec_validator)

validate_spec(data, validator=openapi_v30_spec_validator)

Shouldn't it be replaced in openapi-spec-validator?

sirosen commented 10 months ago

I think I'm experiencing the same thing with readOnly, getting a failure on a simple {"default": "foo", "readOnly": True} when trying to validate my generated OpenAPI data.

I'm having trouble following the code -- this library is the most sophisticated user of jsonschema I have seen -- but I think the relevant bit must be where a default is checked against the schema? (https://github.com/python-openapi/openapi-spec-validator/blob/b0d96b6b9d94b99978a5db4beb9f586026151124/openapi_spec_validator/validation/validators.py#L336)

Is it reasonable to make it possible to opt-out of this check? I can imagine other cases in which someone wants to specify a default of "foo", but users are only allowed to provide enumerated values of ["bar", "baz"], so checking the default will always fail. (Is such a thing forbidden by OpenAPI? It's definitely not forbidden by JSON Schema.)

p1c2u commented 10 months ago

I believe the issue is in default value validation that we shouldn't consider other keywords, including writeonly/readonly.

Based on OpenAPI 3.0, schema type should be the only keyword to be considered here.

The default value represents what would be assumed by the consumer of the input as the value of the schema if one is not provided. Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object defined at the same level. For example, if type is string, then default can be "foo" but cannot be 1.

p1c2u commented 9 months ago

The issue should be fixed with openapi-schema-validator 0.6.2