openapi_parser 0.2.7 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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