Skip to content

Commit

Permalink
support maxProperties and minProperties (#137)
Browse files Browse the repository at this point in the history
https://swagger.io/docs/specification/data-models/data-types/

> The minProperties and maxProperties keywords let you restrict the number of properties allowed in an object. This can be useful when using additionalProperties or free-form objects.
  • Loading branch information
ganmacs authored Nov 15, 2024
1 parent 635ecb3 commit b88556b
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 1 deletion.
22 changes: 22 additions & 0 deletions lib/openapi_parser/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,28 @@ def message
end
end

class LessThanMinProperties < OpenAPIError
def initialize(value, reference)
super(reference)
@value = value
end

def message
"#{@reference} #{@value.size} is less than minProperties value"
end
end

class MoreThanMaxProperties < OpenAPIError
def initialize(value, reference)
super(reference)
@value = value
end

def message
"#{@reference} #{@value.size} is more than maxProperties value"
end
end

class InvalidPattern < OpenAPIError
def initialize(value, pattern, reference, example)
super(reference)
Expand Down
1 change: 1 addition & 0 deletions lib/openapi_parser/schema_validator.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require_relative 'schema_validator/options'
require_relative 'schema_validator/enumable'
require_relative 'schema_validator/minimum_maximum'
require_relative 'schema_validator/properties_number'
require_relative 'schema_validator/base'
require_relative 'schema_validator/string_validator'
require_relative 'schema_validator/integer_validator'
Expand Down
4 changes: 3 additions & 1 deletion lib/openapi_parser/schema_validator/object_validator.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
class OpenAPIParser::SchemaValidator
class ObjectValidator < Base
include ::OpenAPIParser::SchemaValidator::PropertiesNumber

# @param [Hash] value
# @param [OpenAPIParser::Schemas::Schema] schema
# @param [Boolean] parent_all_of true if component is nested under allOf
Expand Down Expand Up @@ -50,7 +52,7 @@ def coerce_and_validate(value, schema, parent_all_of: false, parent_discriminato

value.merge!(coerced_values.to_h) if @coerce_value

[value, nil]
check_properties_number(value, schema)
end
end
end
30 changes: 30 additions & 0 deletions lib/openapi_parser/schema_validator/properties_number.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class OpenAPIParser::SchemaValidator
module PropertiesNumber
# check minProperties and manProperties value by schema
# @param [Object] value
# @param [OpenAPIParser::Schemas::Schema] schema
def check_properties_number(value, schema)
include_properties_num = schema.minProperties || schema.maxProperties
return [value, nil] unless include_properties_num

validate(value, schema)
[value, nil]
rescue OpenAPIParser::OpenAPIError => e
return [nil, e]
end

private

def validate(value, schema)
reference = schema.object_reference

if schema.minProperties && (value.size < schema.minProperties)
raise OpenAPIParser::LessThanMinProperties.new(value, reference)
end

if schema.maxProperties && (value.size > schema.maxProperties)
raise OpenAPIParser::MoreThanMaxProperties.new(value, reference)
end
end
end
end
44 changes: 44 additions & 0 deletions spec/openapi_parser/schema_validator/object_validator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,50 @@
end
end

context 'properties number check' do
let(:root) { OpenAPIParser.parse(schema, {}) }

let(:schema) do
s = build_validate_test_schema(replace_schema)
obj = s['paths']['/validate_test']['post']['requestBody']['content']['application/json']['schema']
obj['maxProperties'] = 3
obj['minProperties'] = 1
s
end

let(:content_type) { 'application/json' }
let(:request_operation) { root.request_operation(:post, '/validate_test') }
let(:params) { { 'query_string' => 'query' } }
let(:replace_schema) { {} }

it { expect(request_operation.validate_request_body(content_type, params)).to eq(params) }

context 'invalid' do
context 'less than minProperties' do
let(:params) { {} }

it do
expect { expect(request_operation.validate_request_body(content_type, params)) }.to raise_error do |e|
expect(e).to be_kind_of(OpenAPIParser::LessThanMinProperties)
expect(e.message).to end_with("0 is less than minProperties value")
end
end
end

context 'more than maxProperties' do
let(:params) { super().merge({ a: 1, b: 1, c: 2 }) }

it do
expect { expect(request_operation.validate_request_body(content_type, params)) }.to raise_error do |e|
p e
expect(e).to be_kind_of(OpenAPIParser::MoreThanMaxProperties)
expect(e.message).to end_with("4 is more than maxProperties value")
end
end
end
end
end

context 'additional_properties check' do
subject { request_operation.validate_request_body(content_type, JSON.load(params.to_json)) }

Expand Down

0 comments on commit b88556b

Please sign in to comment.