Skip to content

Commit b88556b

Browse files
authored
support maxProperties and minProperties (#137)
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.
1 parent 635ecb3 commit b88556b

File tree

5 files changed

+100
-1
lines changed

5 files changed

+100
-1
lines changed

lib/openapi_parser/errors.rb

+22
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,28 @@ def message
160160
end
161161
end
162162

163+
class LessThanMinProperties < OpenAPIError
164+
def initialize(value, reference)
165+
super(reference)
166+
@value = value
167+
end
168+
169+
def message
170+
"#{@reference} #{@value.size} is less than minProperties value"
171+
end
172+
end
173+
174+
class MoreThanMaxProperties < OpenAPIError
175+
def initialize(value, reference)
176+
super(reference)
177+
@value = value
178+
end
179+
180+
def message
181+
"#{@reference} #{@value.size} is more than maxProperties value"
182+
end
183+
end
184+
163185
class InvalidPattern < OpenAPIError
164186
def initialize(value, pattern, reference, example)
165187
super(reference)

lib/openapi_parser/schema_validator.rb

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require_relative 'schema_validator/options'
22
require_relative 'schema_validator/enumable'
33
require_relative 'schema_validator/minimum_maximum'
4+
require_relative 'schema_validator/properties_number'
45
require_relative 'schema_validator/base'
56
require_relative 'schema_validator/string_validator'
67
require_relative 'schema_validator/integer_validator'

lib/openapi_parser/schema_validator/object_validator.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
class OpenAPIParser::SchemaValidator
22
class ObjectValidator < Base
3+
include ::OpenAPIParser::SchemaValidator::PropertiesNumber
4+
35
# @param [Hash] value
46
# @param [OpenAPIParser::Schemas::Schema] schema
57
# @param [Boolean] parent_all_of true if component is nested under allOf
@@ -50,7 +52,7 @@ def coerce_and_validate(value, schema, parent_all_of: false, parent_discriminato
5052

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

53-
[value, nil]
55+
check_properties_number(value, schema)
5456
end
5557
end
5658
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class OpenAPIParser::SchemaValidator
2+
module PropertiesNumber
3+
# check minProperties and manProperties value by schema
4+
# @param [Object] value
5+
# @param [OpenAPIParser::Schemas::Schema] schema
6+
def check_properties_number(value, schema)
7+
include_properties_num = schema.minProperties || schema.maxProperties
8+
return [value, nil] unless include_properties_num
9+
10+
validate(value, schema)
11+
[value, nil]
12+
rescue OpenAPIParser::OpenAPIError => e
13+
return [nil, e]
14+
end
15+
16+
private
17+
18+
def validate(value, schema)
19+
reference = schema.object_reference
20+
21+
if schema.minProperties && (value.size < schema.minProperties)
22+
raise OpenAPIParser::LessThanMinProperties.new(value, reference)
23+
end
24+
25+
if schema.maxProperties && (value.size > schema.maxProperties)
26+
raise OpenAPIParser::MoreThanMaxProperties.new(value, reference)
27+
end
28+
end
29+
end
30+
end

spec/openapi_parser/schema_validator/object_validator_spec.rb

+44
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,50 @@
249249
end
250250
end
251251

252+
context 'properties number check' do
253+
let(:root) { OpenAPIParser.parse(schema, {}) }
254+
255+
let(:schema) do
256+
s = build_validate_test_schema(replace_schema)
257+
obj = s['paths']['/validate_test']['post']['requestBody']['content']['application/json']['schema']
258+
obj['maxProperties'] = 3
259+
obj['minProperties'] = 1
260+
s
261+
end
262+
263+
let(:content_type) { 'application/json' }
264+
let(:request_operation) { root.request_operation(:post, '/validate_test') }
265+
let(:params) { { 'query_string' => 'query' } }
266+
let(:replace_schema) { {} }
267+
268+
it { expect(request_operation.validate_request_body(content_type, params)).to eq(params) }
269+
270+
context 'invalid' do
271+
context 'less than minProperties' do
272+
let(:params) { {} }
273+
274+
it do
275+
expect { expect(request_operation.validate_request_body(content_type, params)) }.to raise_error do |e|
276+
expect(e).to be_kind_of(OpenAPIParser::LessThanMinProperties)
277+
expect(e.message).to end_with("0 is less than minProperties value")
278+
end
279+
end
280+
end
281+
282+
context 'more than maxProperties' do
283+
let(:params) { super().merge({ a: 1, b: 1, c: 2 }) }
284+
285+
it do
286+
expect { expect(request_operation.validate_request_body(content_type, params)) }.to raise_error do |e|
287+
p e
288+
expect(e).to be_kind_of(OpenAPIParser::MoreThanMaxProperties)
289+
expect(e.message).to end_with("4 is more than maxProperties value")
290+
end
291+
end
292+
end
293+
end
294+
end
295+
252296
context 'additional_properties check' do
253297
subject { request_operation.validate_request_body(content_type, JSON.load(params.to_json)) }
254298

0 commit comments

Comments
 (0)