From b0a084a42f9186a21320300d6ba47a8c88543e5c Mon Sep 17 00:00:00 2001 From: David Garcia Date: Thu, 12 Sep 2024 17:23:07 +0200 Subject: [PATCH 1/2] Handle read only --- lib/openapi_parser.rb | 6 +++--- lib/openapi_parser/config.rb | 8 +++++++- lib/openapi_parser/schema_validator.rb | 3 ++- .../schema_validator/object_validator.rb | 10 ++++++++++ lib/openapi_parser/schema_validator/options.rb | 7 +++++-- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/openapi_parser.rb b/lib/openapi_parser.rb index 011d46a..92a161b 100644 --- a/lib/openapi_parser.rb +++ b/lib/openapi_parser.rb @@ -82,13 +82,13 @@ def parse_file(content, ext) def parse_yaml(content) # FIXME: when drop ruby 2.5, we should use permitted_classes - (Gem::Version.create(RUBY_VERSION) < Gem::Version.create("2.6.0")) ? - Psych.safe_load(content, [Date, Time]) : + (Gem::Version.create(RUBY_VERSION) < Gem::Version.create("2.6.0")) ? + Psych.safe_load(content, [Date, Time]) : Psych.safe_load(content, permitted_classes: [Date, Time]) end def parse_json(content) - raise "json content is nil" unless content + raise "json content is nil" unless content JSON.parse(content) end diff --git a/lib/openapi_parser/config.rb b/lib/openapi_parser/config.rb index faf6008..c8cf490 100644 --- a/lib/openapi_parser/config.rb +++ b/lib/openapi_parser/config.rb @@ -37,11 +37,17 @@ def validate_header @config.fetch(:validate_header, true) end + # TODO: in a major version update, change this to default to `ignore`. + def handle_readOnly + @config.fetch(:handle_readOnly, nil) + end + # @return [OpenAPIParser::SchemaValidator::Options] def request_validator_options @request_validator_options ||= OpenAPIParser::SchemaValidator::Options.new(coerce_value: coerce_value, datetime_coerce_class: datetime_coerce_class, - validate_header: validate_header) + validate_header: validate_header, + handle_readOnly: handle_readOnly) end alias_method :request_body_options, :request_validator_options diff --git a/lib/openapi_parser/schema_validator.rb b/lib/openapi_parser/schema_validator.rb index fd9d2af..aa5c1af 100644 --- a/lib/openapi_parser/schema_validator.rb +++ b/lib/openapi_parser/schema_validator.rb @@ -54,6 +54,7 @@ def initialize(value, schema, options) @schema = schema @coerce_value = options.coerce_value @datetime_coerce_class = options.datetime_coerce_class + @handle_readOnly = options.handle_readOnly end # execute validate data @@ -135,7 +136,7 @@ def boolean_validator end def object_validator - @object_validator ||= OpenAPIParser::SchemaValidator::ObjectValidator.new(self, @coerce_value) + @object_validator ||= OpenAPIParser::SchemaValidator::ObjectValidator.new(self, @coerce_value, @handle_readOnly) end def array_validator diff --git a/lib/openapi_parser/schema_validator/object_validator.rb b/lib/openapi_parser/schema_validator/object_validator.rb index 1ee355e..e823245 100644 --- a/lib/openapi_parser/schema_validator/object_validator.rb +++ b/lib/openapi_parser/schema_validator/object_validator.rb @@ -1,5 +1,10 @@ class OpenAPIParser::SchemaValidator class ObjectValidator < Base + + def initialize(validator, coerce_value, handle_readOnly) + super(validator, coerce_value) + @handle_readOnly = handle_readOnly + end # @param [Hash] value # @param [OpenAPIParser::Schemas::Schema] schema # @param [Boolean] parent_all_of true if component is nested under allOf @@ -10,6 +15,11 @@ def coerce_and_validate(value, schema, parent_all_of: false, parent_discriminato properties = schema.properties || {} required_set = schema.required ? schema.required.to_set : Set.new + + if @handle_readOnly == :ignore + required_set.reject! { |name| schema.properties[name]&.read_only == true } + end + remaining_keys = value.keys if schema.discriminator && !parent_discriminator_schemas.include?(schema) diff --git a/lib/openapi_parser/schema_validator/options.rb b/lib/openapi_parser/schema_validator/options.rb index 6824f03..0d24aea 100644 --- a/lib/openapi_parser/schema_validator/options.rb +++ b/lib/openapi_parser/schema_validator/options.rb @@ -6,12 +6,15 @@ class Options # @return [Object, nil] coerce datetime string by this Object class # @!attribute [r] validate_header # @return [Boolean] validate header or not - attr_reader :coerce_value, :datetime_coerce_class, :validate_header + # @!attribute [r] handle_readOnly + # @return [Object, nil] How to use readOnly property to process requests. Either :ignore or :raise + attr_reader :coerce_value, :datetime_coerce_class, :validate_header, :handle_readOnly - def initialize(coerce_value: nil, datetime_coerce_class: nil, validate_header: true) + def initialize(coerce_value: nil, datetime_coerce_class: nil, validate_header: true, handle_readOnly: nil) @coerce_value = coerce_value @datetime_coerce_class = datetime_coerce_class @validate_header = validate_header + @handle_readOnly = handle_readOnly end end From a86c5fcfb1d50eef004be000f6da5b39049cc6dd Mon Sep 17 00:00:00 2001 From: David Garcia Date: Thu, 12 Sep 2024 18:02:20 +0200 Subject: [PATCH 2/2] Don't validate readOnly properties --- lib/openapi_parser/schema_validator/object_validator.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/openapi_parser/schema_validator/object_validator.rb b/lib/openapi_parser/schema_validator/object_validator.rb index e823245..1e3be21 100644 --- a/lib/openapi_parser/schema_validator/object_validator.rb +++ b/lib/openapi_parser/schema_validator/object_validator.rb @@ -17,7 +17,11 @@ def coerce_and_validate(value, schema, parent_all_of: false, parent_discriminato required_set = schema.required ? schema.required.to_set : Set.new if @handle_readOnly == :ignore - required_set.reject! { |name| schema.properties[name]&.read_only == true } + schema.properties.each do |name, property_value| + next unless property_value.read_only + required_set.delete(name) + value.delete(name) + end end remaining_keys = value.keys