openapi_parser 0.2.7 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2dd37ca24b93c63b4ccb98a693c9200f1850fca3349b5e70931aa40771bb31dc
4
- data.tar.gz: c7d4e29d589c610554a8873a601d8eba674560267ccdb28a951ec120debbb0a0
3
+ metadata.gz: cc1cad9d7c07f7d5ce382429089820959ac182353a6b8daf545fc6408384af85
4
+ data.tar.gz: 00bef8afe01fbfddf5feceec03ef7bd1daba208ea0efce36b1413bbd2be28e32
5
5
  SHA512:
6
- metadata.gz: a8c5ce03e3a6399403b3018f3fb5b6d3b0ff304989ac83a1c4aedb1a83709285f2a80abf90b25ac99ea5623474f7070239e62a918535f8798de2c73d1527c0fe
7
- data.tar.gz: 85dda1a6fff6458ca87f462ede780a933448e05188e4d514c415abee3e36a365ba956e57684748c65103a83321a1760f5433ef9f909fcb5fc2178def664eccc9
6
+ metadata.gz: e9888a1912dc0ea3bace51771ee7524492bbb152a765b5c312c39bb94af3bfe17b108899c567377a1e1e51fc426804c94beb0bd0156d14561e9c1e7dc0229fe0
7
+ data.tar.gz: 95111afc9c980cc707cc81cfe4551ade4aadd0e24e69c9bb951d92c293806b63983e535a0ba7ea5d16f1c6bf8decb053f114c98b7114b00108c494972868e9cb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  ## Unreleased
2
2
 
3
+ ## 0.3.0 (2019-06-01)
4
+
5
+ ### features
6
+ * Perform a strict check on object properties (#33)
7
+
8
+ ### Bugfix
9
+ * Support discriminator without mapping (#35)
10
+ * Fix upper case request param validation (#38)
11
+
3
12
  ## 0.2.7 (2019-05-20)
4
13
  * Fix for release miss
5
14
 
@@ -43,14 +43,25 @@ module OpenAPIParser
43
43
  end
44
44
  end
45
45
 
46
- class NotExistDiscriminatorMappingTarget < OpenAPIError
47
- def initialize(key, reference)
46
+ class NotExistPropertyDefinition < OpenAPIError
47
+ def initialize(keys, reference)
48
+ super(reference)
49
+ @keys = keys
50
+ end
51
+
52
+ def message
53
+ "properties #{@keys.join(",")} are not defined in #{@reference}"
54
+ end
55
+ end
56
+
57
+ class NotExistDiscriminatorMappedSchema < OpenAPIError
58
+ def initialize(mapped_schema_reference, reference)
48
59
  super(reference)
49
- @key = key
60
+ @mapped_schema_reference = mapped_schema_reference
50
61
  end
51
62
 
52
63
  def message
53
- "discriminator mapping key #{@key} does not exist in #{@reference}"
64
+ "discriminator mapped schema #{@mapped_schema_reference} does not exist in #{@reference}"
54
65
  end
55
66
  end
56
67
 
@@ -8,9 +8,9 @@ class OpenAPIParser::ParameterValidator
8
8
  def validate_parameter(parameters_hash, params, object_reference, options, is_header = false)
9
9
  no_exist_required_key = []
10
10
 
11
- params_key_converted = params.keys.map { |k| [(is_header ? k&.downcase : k), k] }.to_h
11
+ params_key_converted = params.keys.map { |k| [convert_key(k, is_header), k] }.to_h
12
12
  parameters_hash.each do |k, v|
13
- key = params_key_converted[k.downcase]
13
+ key = params_key_converted[convert_key(k, is_header)]
14
14
  if params.include?(key)
15
15
  coerced = v.validate_params(params[key], options)
16
16
  params[key] = coerced if options.coerce_value
@@ -23,5 +23,11 @@ class OpenAPIParser::ParameterValidator
23
23
 
24
24
  params
25
25
  end
26
+
27
+ private
28
+
29
+ def convert_key(k, is_header)
30
+ is_header ? k&.downcase : k
31
+ end
26
32
  end
27
33
  end
@@ -18,7 +18,7 @@ class OpenAPIParser::SchemaValidator
18
18
  # @param [Object] value
19
19
  # @param [OpenAPIParser::Schemas::Schema] schema
20
20
  module Validatable
21
- def validate_schema(value, schema)
21
+ def validate_schema(value, schema, **keyword_args)
22
22
  raise 'implement'
23
23
  end
24
24
 
@@ -66,11 +66,15 @@ class OpenAPIParser::SchemaValidator
66
66
  # validate value eby schema
67
67
  # @param [Object] value
68
68
  # @param [OpenAPIParser::Schemas::Schema] schema
69
- def validate_schema(value, schema)
69
+ def validate_schema(value, schema, **keyword_args)
70
70
  return [value, nil] unless schema
71
71
 
72
72
  if (v = validator(value, schema))
73
- return v.coerce_and_validate(value, schema)
73
+ if keyword_args.empty?
74
+ return v.coerce_and_validate(value, schema)
75
+ else
76
+ return v.coerce_and_validate(value, schema, **keyword_args)
77
+ end
74
78
  end
75
79
 
76
80
  # unknown return error
@@ -4,12 +4,31 @@ class OpenAPIParser::SchemaValidator
4
4
  # coerce and validate value
5
5
  # @param [Object] value
6
6
  # @param [OpenAPIParser::Schemas::Schema] schema
7
- def coerce_and_validate(value, schema)
7
+ def coerce_and_validate(value, schema, **_keyword_args)
8
8
  # if any schema return error, it's not valida all of value
9
+ remaining_keys = value.kind_of?(Hash) ? value.keys : []
10
+ nested_additional_properties = false
9
11
  schema.all_of.each do |s|
10
- _coerced, err = validatable.validate_schema(value, s)
12
+ # We need to store the reference to all of, so we can perform strict check on allowed properties
13
+ _coerced, err = validatable.validate_schema(value, s, :parent_all_of => true)
14
+
15
+ if s.type == "object"
16
+ remaining_keys -= (s.properties || {}).keys
17
+ nested_additional_properties = true if s.additional_properties
18
+ else
19
+ # If this is not allOf having array of objects inside, but e.g. having another anyOf/oneOf nested
20
+ remaining_keys.clear
21
+ end
22
+
11
23
  return [nil, err] if err
12
24
  end
25
+
26
+ # If there are nested additionalProperites, we allow not defined extra properties and lean on the specific
27
+ # additionalProperties validation
28
+ if !nested_additional_properties && !remaining_keys.empty?
29
+ return [nil, OpenAPIParser::NotExistPropertyDefinition.new(remaining_keys, schema.object_reference)]
30
+ end
31
+
13
32
  [value, nil]
14
33
  end
15
34
  end
@@ -2,7 +2,7 @@ class OpenAPIParser::SchemaValidator
2
2
  class AnyOfValidator < Base
3
3
  # @param [Object] value
4
4
  # @param [OpenAPIParser::Schemas::Schema] schema
5
- def coerce_and_validate(value, schema)
5
+ def coerce_and_validate(value, schema, **_keyword_args)
6
6
  if schema.discriminator
7
7
  return validate_discriminator_schema(schema.discriminator, value)
8
8
  end
@@ -2,7 +2,7 @@ class OpenAPIParser::SchemaValidator
2
2
  class ArrayValidator < Base
3
3
  # @param [Array] value
4
4
  # @param [OpenAPIParser::Schemas::Schema] schema
5
- def coerce_and_validate(value, schema)
5
+ def coerce_and_validate(value, schema, **_keyword_args)
6
6
  return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(Array)
7
7
 
8
8
  # array type have an schema in items property
@@ -14,7 +14,7 @@ class OpenAPIParser::SchemaValidator
14
14
  # need override
15
15
  # @param [Array] _value
16
16
  # @param [OpenAPIParser::Schemas::Schema] _schema
17
- def coerce_and_validate(_value, _schema)
17
+ def coerce_and_validate(_value, _schema, **_keyword_args)
18
18
  raise 'need implement'
19
19
  end
20
20
 
@@ -24,16 +24,17 @@ class OpenAPIParser::SchemaValidator
24
24
  end
25
25
  mapping_key = value[discriminator.property_name]
26
26
 
27
- # TODO: it's allowed to have discriminator without mapping, then we need to lookup discriminator.property_name
27
+ # it's allowed to have discriminator without mapping, then we need to lookup discriminator.property_name
28
28
  # but the format is not the full path, just model name in the components
29
- mapping_target = discriminator.mapping[mapping_key]
30
- unless mapping_target
31
- return [nil, OpenAPIParser::NotExistDiscriminatorMappingTarget.new(mapping_key, discriminator.object_reference)]
32
- end
29
+ mapping_target = discriminator.mapping&.[](mapping_key) || "#/components/schemas/#{mapping_key}"
33
30
 
34
31
  # Find object does O(n) search at worst, then caches the result, so this is ok for repeated search
35
32
  resolved_schema = discriminator.root.find_object(mapping_target)
36
- validatable.validate_schema(value, resolved_schema)
33
+
34
+ unless resolved_schema
35
+ return [nil, OpenAPIParser::NotExistDiscriminatorMappedSchema.new(mapping_target, discriminator.object_reference)]
36
+ end
37
+ validatable.validate_schema(value, resolved_schema, {discriminator_property_name: discriminator.property_name})
37
38
  end
38
39
  end
39
40
  end
@@ -3,7 +3,7 @@ class OpenAPIParser::SchemaValidator
3
3
  TRUE_VALUES = ['true', '1'].freeze
4
4
  FALSE_VALUES = ['false', '0'].freeze
5
5
 
6
- def coerce_and_validate(value, schema)
6
+ def coerce_and_validate(value, schema, **_keyword_args)
7
7
  value = coerce(value) if @coerce_value
8
8
 
9
9
  return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(TrueClass) || value.kind_of?(FalseClass)
@@ -5,7 +5,7 @@ class OpenAPIParser::SchemaValidator
5
5
  # validate float value by schema
6
6
  # @param [Object] value
7
7
  # @param [OpenAPIParser::Schemas::Schema] schema
8
- def coerce_and_validate(value, schema)
8
+ def coerce_and_validate(value, schema, **_keyword_args)
9
9
  value = coerce(value) if @coerce_value
10
10
 
11
11
  return validatable.validate_integer(value, schema) if value.kind_of?(Integer)
@@ -5,7 +5,7 @@ class OpenAPIParser::SchemaValidator
5
5
  # validate integer value by schema
6
6
  # @param [Object] value
7
7
  # @param [OpenAPIParser::Schemas::Schema] schema
8
- def coerce_and_validate(value, schema)
8
+ def coerce_and_validate(value, schema, **_keyword_args)
9
9
  value = coerce(value) if @coerce_value
10
10
 
11
11
  return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(Integer)
@@ -2,7 +2,7 @@ class OpenAPIParser::SchemaValidator
2
2
  class NilValidator < Base
3
3
  # @param [Object] value
4
4
  # @param [OpenAPIParser::Schemas::Schema] schema
5
- def coerce_and_validate(value, schema)
5
+ def coerce_and_validate(value, schema, **_keyword_args)
6
6
  return [value, nil] if schema.nullable
7
7
 
8
8
  [nil, OpenAPIParser::NotNullError.new(schema.object_reference)]
@@ -2,22 +2,40 @@ class OpenAPIParser::SchemaValidator
2
2
  class ObjectValidator < Base
3
3
  # @param [Hash] value
4
4
  # @param [OpenAPIParser::Schemas::Schema] schema
5
- def coerce_and_validate(value, schema)
5
+ # @param [Boolean] parent_all_of true if component is nested under allOf
6
+ # @param [String, nil] discriminator_property_name discriminator.property_name to ignore checking additional_properties
7
+ def coerce_and_validate(value, schema, parent_all_of: false, discriminator_property_name: nil)
6
8
  return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(Hash)
7
9
 
8
10
  return [value, nil] unless schema.properties
9
11
 
10
12
  required_set = schema.required ? schema.required.to_set : Set.new
13
+ remaining_keys = value.keys
11
14
 
12
15
  coerced_values = value.map do |name, v|
13
16
  s = schema.properties[name]
14
- coerced, err = validatable.validate_schema(v, s)
17
+ coerced, err = if s
18
+ remaining_keys.delete(name)
19
+ validatable.validate_schema(v, s)
20
+ else
21
+ # TODO: we need to perform a validation based on schema.additional_properties here, if
22
+ # additionalProperties are defined
23
+ [v, nil]
24
+ end
25
+
15
26
  return [nil, err] if err
16
27
 
17
28
  required_set.delete(name)
18
29
  [name, coerced]
19
30
  end
20
31
 
32
+ remaining_keys.delete(discriminator_property_name) if discriminator_property_name
33
+
34
+ if !remaining_keys.empty? && !parent_all_of && !schema.additional_properties
35
+ # If object is nested in all of, the validation is already done in allOf validator. Or if
36
+ # additionalProperties are defined, we will validate using that
37
+ return [nil, OpenAPIParser::NotExistPropertyDefinition.new(remaining_keys, schema.object_reference)]
38
+ end
21
39
  return [nil, OpenAPIParser::NotExistRequiredKey.new(required_set.to_a, schema.object_reference)] unless required_set.empty?
22
40
 
23
41
  value.merge!(coerced_values.to_h) if @coerce_value
@@ -2,7 +2,7 @@ class OpenAPIParser::SchemaValidator
2
2
  class OneOfValidator < Base
3
3
  # @param [Object] value
4
4
  # @param [OpenAPIParser::Schemas::Schema] schema
5
- def coerce_and_validate(value, schema)
5
+ def coerce_and_validate(value, schema, **_keyword_args)
6
6
  if schema.discriminator
7
7
  return validate_discriminator_schema(schema.discriminator, value)
8
8
  end
@@ -7,7 +7,7 @@ class OpenAPIParser::SchemaValidator
7
7
  @datetime_coerce_class = datetime_coerce_class
8
8
  end
9
9
 
10
- def coerce_and_validate(value, schema)
10
+ def coerce_and_validate(value, schema, **_keyword_args)
11
11
  return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(String)
12
12
 
13
13
  value, err = check_enum_include(value, schema)
@@ -1,3 +1,3 @@
1
1
  module OpenAPIParser
2
- VERSION = '0.2.7'.freeze
2
+ VERSION = '0.3.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ota42y
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-20 00:00:00.000000000 Z
11
+ date: 2019-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler