openapi_parser 0.12.1 → 0.15.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.
@@ -5,25 +5,26 @@ module OpenAPIParser::Findable
5
5
  # @param [String] reference
6
6
  # @return [OpenAPIParser::Findable]
7
7
  def find_object(reference)
8
- reference = CGI.unescape(reference)
9
8
  return self if object_reference == reference
10
9
  remote_reference = !reference.start_with?('#')
11
10
  return find_remote_object(reference) if remote_reference
12
11
  return nil unless reference.start_with?(object_reference)
13
12
 
13
+ unescaped_reference = CGI.unescape(reference)
14
+
14
15
  @find_object_cache = {} unless defined? @find_object_cache
15
- if (obj = @find_object_cache[reference])
16
+ if (obj = @find_object_cache[unescaped_reference])
16
17
  return obj
17
18
  end
18
19
 
19
- if (child = _openapi_all_child_objects[reference])
20
- @find_object_cache[reference] = child
20
+ if (child = _openapi_all_child_objects[unescaped_reference])
21
+ @find_object_cache[unescaped_reference] = child
21
22
  return child
22
23
  end
23
24
 
24
25
  _openapi_all_child_objects.values.each do |c|
25
- if (obj = c.find_object(reference))
26
- @find_object_cache[reference] = obj
26
+ if (obj = c.find_object(unescaped_reference))
27
+ @find_object_cache[unescaped_reference] = obj
27
28
  return obj
28
29
  end
29
30
  end
@@ -45,8 +46,8 @@ module OpenAPIParser::Findable
45
46
  private
46
47
 
47
48
  def find_remote_object(reference)
48
- reference_uri = URI(reference)
49
- fragment = reference_uri.fragment
49
+ uri, fragment = reference.split("#", 2)
50
+ reference_uri = URI(uri)
50
51
  reference_uri.fragment = nil
51
52
  root.load_another_schema(reference_uri)&.find_object("##{fragment}")
52
53
  end
@@ -13,6 +13,12 @@ module OpenAPIParser::ParameterValidatable
13
13
  validate_query_parameter(params, object_reference, options)
14
14
  end
15
15
 
16
+ # @param [PathItem] path_item parent
17
+ def set_parent_path_item(path_item)
18
+ @merged_parameter = (parameters || []) + (path_item.parameters || [])
19
+ nil
20
+ end
21
+
16
22
  private
17
23
 
18
24
  # @param [Hash] params query parameter hash
@@ -44,7 +50,7 @@ module OpenAPIParser::ParameterValidatable
44
50
  # @return [Hash{String => Hash{String => Parameter}}] hash[in][name] => Parameter
45
51
  def divided_parameter_hash
46
52
  @divided_parameter_hash ||=
47
- (parameters || []).
53
+ (@merged_parameter || []).
48
54
  group_by(&:in).
49
55
  map { |in_type, params| # rubocop:disable Style/BlockDelimiters
50
56
  [
@@ -13,7 +13,7 @@ module OpenAPIParser
13
13
  end
14
14
 
15
15
  def message
16
- "#{@reference} expected #{@type}, but received #{@data.class}: #{@data}"
16
+ "#{@reference} expected #{@type}, but received #{@data.class}: #{@data.inspect}"
17
17
  end
18
18
 
19
19
  class << self
@@ -73,7 +73,7 @@ module OpenAPIParser
73
73
  end
74
74
 
75
75
  def message
76
- "discriminator propertyName #{@key} does not exist in value #{@value} in #{@reference}"
76
+ "discriminator propertyName #{@key} does not exist in value #{@value.inspect} in #{@reference}"
77
77
  end
78
78
  end
79
79
 
@@ -84,7 +84,7 @@ module OpenAPIParser
84
84
  end
85
85
 
86
86
  def message
87
- "#{@value} isn't one of in #{@reference}"
87
+ "#{@value.inspect} isn't one of in #{@reference}"
88
88
  end
89
89
  end
90
90
 
@@ -95,7 +95,7 @@ module OpenAPIParser
95
95
  end
96
96
 
97
97
  def message
98
- "#{@value} isn't any of in #{@reference}"
98
+ "#{@value.inspect} isn't any of in #{@reference}"
99
99
  end
100
100
  end
101
101
 
@@ -106,7 +106,7 @@ module OpenAPIParser
106
106
  end
107
107
 
108
108
  def message
109
- "#{@value} isn't include enum in #{@reference}"
109
+ "#{@value.inspect} isn't part of the enum in #{@reference}"
110
110
  end
111
111
  end
112
112
 
@@ -117,7 +117,7 @@ module OpenAPIParser
117
117
  end
118
118
 
119
119
  def message
120
- "#{@reference} #{@value} is less than minimum value"
120
+ "#{@reference} #{@value.inspect} is less than minimum value"
121
121
  end
122
122
  end
123
123
 
@@ -128,7 +128,7 @@ module OpenAPIParser
128
128
  end
129
129
 
130
130
  def message
131
- "#{@reference} #{@value} cannot be less than or equal to exclusive minimum value"
131
+ "#{@reference} #{@value.inspect} cannot be less than or equal to exclusive minimum value"
132
132
  end
133
133
  end
134
134
 
@@ -139,7 +139,7 @@ module OpenAPIParser
139
139
  end
140
140
 
141
141
  def message
142
- "#{@reference} #{@value} is more than maximum value"
142
+ "#{@reference} #{@value.inspect} is more than maximum value"
143
143
  end
144
144
  end
145
145
 
@@ -150,7 +150,7 @@ module OpenAPIParser
150
150
  end
151
151
 
152
152
  def message
153
- "#{@reference} #{@value} cannot be more than or equal to exclusive maximum value"
153
+ "#{@reference} #{@value.inspect} cannot be more than or equal to exclusive maximum value"
154
154
  end
155
155
  end
156
156
 
@@ -163,7 +163,7 @@ module OpenAPIParser
163
163
  end
164
164
 
165
165
  def message
166
- "#{@reference} pattern #{@pattern} does not match value: #{@value}#{@example ? ", example: #{@example}" : ""}"
166
+ "#{@reference} pattern #{@pattern} does not match value: #{@value.inspect}#{@example ? ", example: #{@example}" : ""}"
167
167
  end
168
168
  end
169
169
 
@@ -174,7 +174,7 @@ module OpenAPIParser
174
174
  end
175
175
 
176
176
  def message
177
- "#{@reference} email address format does not match value: #{@value}"
177
+ "#{@reference} email address format does not match value: #{@value.inspect}"
178
178
  end
179
179
  end
180
180
 
@@ -185,7 +185,18 @@ module OpenAPIParser
185
185
  end
186
186
 
187
187
  def message
188
- "#{@reference} Value: #{@value} is not conformant with UUID format"
188
+ "#{@reference} Value: #{@value.inspect} is not conformant with UUID format"
189
+ end
190
+ end
191
+
192
+ class InvalidDateFormat < OpenAPIError
193
+ def initialize(value, reference)
194
+ super(reference)
195
+ @value = value
196
+ end
197
+
198
+ def message
199
+ "#{@reference} Value: #{@value.inspect} is not conformant with date format"
189
200
  end
190
201
  end
191
202
 
@@ -208,7 +219,7 @@ module OpenAPIParser
208
219
  end
209
220
 
210
221
  def message
211
- "#{@reference} #{@value} is longer than max length"
222
+ "#{@reference} #{@value.inspect} is longer than max length"
212
223
  end
213
224
  end
214
225
 
@@ -219,7 +230,7 @@ module OpenAPIParser
219
230
  end
220
231
 
221
232
  def message
222
- "#{@reference} #{@value} is shorter than min length"
233
+ "#{@reference} #{@value.inspect} is shorter than min length"
223
234
  end
224
235
  end
225
236
 
@@ -230,7 +241,7 @@ module OpenAPIParser
230
241
  end
231
242
 
232
243
  def message
233
- "#{@reference} #{@value} contains more than max items"
244
+ "#{@reference} #{@value.inspect} contains more than max items"
234
245
  end
235
246
  end
236
247
 
@@ -241,7 +252,7 @@ module OpenAPIParser
241
252
  end
242
253
 
243
254
  def message
244
- "#{@reference} #{@value} contains fewer than min items"
255
+ "#{@reference} #{@value.inspect} contains fewer than min items"
245
256
  end
246
257
  end
247
258
  end
@@ -136,7 +136,7 @@ class OpenAPIParser::PathItemFinder
136
136
  end
137
137
  end
138
138
 
139
- # find mathing path and extract params
139
+ # find matching path and extract params
140
140
  # EXAMPLE: find_path_and_params('get', '/user/1') => ['/user/{id}', { 'id' => 1 }]
141
141
  def find_path_and_params(http_method, request_path)
142
142
  return [request_path, {}] if matches_directly?(request_path, http_method)
@@ -65,7 +65,6 @@ class OpenAPIParser::RequestOperation
65
65
  # @param [OpenAPIParser::SchemaValidator::Options] options request validator options
66
66
  def validate_request_parameter(params, headers, options = nil)
67
67
  options ||= config.request_validator_options
68
- path_item&.validate_request_parameter(params, headers, options)
69
68
  operation_object&.validate_request_parameter(params, headers, options)
70
69
  end
71
70
 
@@ -12,6 +12,7 @@ require_relative 'schema_validators/any_of_validator'
12
12
  require_relative 'schema_validators/all_of_validator'
13
13
  require_relative 'schema_validators/one_of_validator'
14
14
  require_relative 'schema_validators/nil_validator'
15
+ require_relative 'schema_validators/unspecified_type_validator'
15
16
 
16
17
  class OpenAPIParser::SchemaValidator
17
18
  # validate value by schema
@@ -113,7 +114,7 @@ class OpenAPIParser::SchemaValidator
113
114
  when 'array'
114
115
  array_validator
115
116
  else
116
- nil
117
+ unspecified_type_validator
117
118
  end
118
119
  end
119
120
 
@@ -156,4 +157,8 @@ class OpenAPIParser::SchemaValidator
156
157
  def nil_validator
157
158
  @nil_validator ||= OpenAPIParser::SchemaValidator::NilValidator.new(self, @coerce_value)
158
159
  end
160
+
161
+ def unspecified_type_validator
162
+ @unspecified_type_validator ||= OpenAPIParser::SchemaValidator::UnspecifiedTypeValidator.new(self, @coerce_value)
163
+ end
159
164
  end
@@ -4,13 +4,18 @@ 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, **_keyword_args)
7
+ def coerce_and_validate(value, schema, **keyword_args)
8
8
  # if any schema return error, it's not valida all of value
9
9
  remaining_keys = value.kind_of?(Hash) ? value.keys : []
10
10
  nested_additional_properties = false
11
11
  schema.all_of.each do |s|
12
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)
13
+ _coerced, err = validatable.validate_schema(
14
+ value,
15
+ s,
16
+ :parent_all_of => true,
17
+ parent_discriminator_schemas: keyword_args[:parent_discriminator_schemas]
18
+ )
14
19
 
15
20
  if s.type == "object"
16
21
  remaining_keys -= (s.properties || {}).keys
@@ -18,7 +18,7 @@ class OpenAPIParser::SchemaValidator
18
18
  raise 'need implement'
19
19
  end
20
20
 
21
- def validate_discriminator_schema(discriminator, value)
21
+ def validate_discriminator_schema(discriminator, value, parent_discriminator_schemas: [])
22
22
  unless value.key?(discriminator.property_name)
23
23
  return [nil, OpenAPIParser::NotExistDiscriminatorPropertyName.new(discriminator.property_name, value, discriminator.object_reference)]
24
24
  end
@@ -34,7 +34,11 @@ class OpenAPIParser::SchemaValidator
34
34
  unless resolved_schema
35
35
  return [nil, OpenAPIParser::NotExistDiscriminatorMappedSchema.new(mapping_target, discriminator.object_reference)]
36
36
  end
37
- validatable.validate_schema(value, resolved_schema, **{discriminator_property_name: discriminator.property_name})
37
+ validatable.validate_schema(
38
+ value,
39
+ resolved_schema,
40
+ **{discriminator_property_name: discriminator.property_name, parent_discriminator_schemas: parent_discriminator_schemas}
41
+ )
38
42
  end
39
43
  end
40
44
  end
@@ -1,5 +1,7 @@
1
1
  class OpenAPIParser::SchemaValidator
2
2
  class BooleanValidator < Base
3
+ include ::OpenAPIParser::SchemaValidator::Enumable
4
+
3
5
  TRUE_VALUES = ['true', '1'].freeze
4
6
  FALSE_VALUES = ['false', '0'].freeze
5
7
 
@@ -8,6 +10,9 @@ class OpenAPIParser::SchemaValidator
8
10
 
9
11
  return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(TrueClass) || value.kind_of?(FalseClass)
10
12
 
13
+ value, err = check_enum_include(value, schema)
14
+ return [nil, err] if err
15
+
11
16
  [value, nil]
12
17
  end
13
18
 
@@ -21,14 +21,14 @@ class OpenAPIParser::SchemaValidator
21
21
 
22
22
  value, err = check_enum_include(value, schema)
23
23
  return [nil, err] if err
24
-
24
+
25
25
  check_minimum_maximum(value, schema)
26
26
  end
27
27
 
28
28
  def coerce(value)
29
29
  Float(value)
30
- rescue ArgumentError => e
31
- raise e unless e.message =~ /invalid value for Float/
30
+ rescue ArgumentError, TypeError
31
+ value
32
32
  end
33
33
  end
34
34
  end
@@ -23,12 +23,10 @@ class OpenAPIParser::SchemaValidator
23
23
  return value if value.kind_of?(Integer)
24
24
 
25
25
  begin
26
- return Integer(value)
27
- rescue ArgumentError => e
28
- raise e unless e.message =~ /invalid value for Integer/
26
+ Integer(value)
27
+ rescue ArgumentError, TypeError
28
+ value
29
29
  end
30
-
31
- value
32
30
  end
33
31
  end
34
32
  end
@@ -4,7 +4,7 @@ class OpenAPIParser::SchemaValidator
4
4
  # @param [OpenAPIParser::Schemas::Schema] schema
5
5
  # @param [Boolean] parent_all_of true if component is nested under allOf
6
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)
7
+ def coerce_and_validate(value, schema, parent_all_of: false, parent_discriminator_schemas: [], discriminator_property_name: nil)
8
8
  return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(Hash)
9
9
 
10
10
  properties = schema.properties || {}
@@ -12,6 +12,16 @@ class OpenAPIParser::SchemaValidator
12
12
  required_set = schema.required ? schema.required.to_set : Set.new
13
13
  remaining_keys = value.keys
14
14
 
15
+ if schema.discriminator && !parent_discriminator_schemas.include?(schema)
16
+ return validate_discriminator_schema(
17
+ schema.discriminator,
18
+ value,
19
+ parent_discriminator_schemas: parent_discriminator_schemas + [schema]
20
+ )
21
+ else
22
+ remaining_keys.delete('discriminator')
23
+ end
24
+
15
25
  coerced_values = value.map do |name, v|
16
26
  s = properties[name]
17
27
  coerced, err = if s
@@ -30,6 +30,9 @@ class OpenAPIParser::SchemaValidator
30
30
  value, err = validate_uuid_format(value, schema)
31
31
  return [nil, err] if err
32
32
 
33
+ value, err = validate_date_format(value, schema)
34
+ return [nil, err] if err
35
+
33
36
  [value, nil]
34
37
  end
35
38
 
@@ -86,5 +89,17 @@ class OpenAPIParser::SchemaValidator
86
89
 
87
90
  return [nil, OpenAPIParser::InvalidUUIDFormat.new(value, schema.object_reference)]
88
91
  end
92
+
93
+ def validate_date_format(value, schema)
94
+ return [value, nil] unless schema.format == 'date'
95
+
96
+ begin
97
+ Date.strptime(value, "%Y-%m-%d")
98
+ rescue ArgumentError
99
+ return [nil, OpenAPIParser::InvalidDateFormat.new(value, schema.object_reference)]
100
+ end
101
+
102
+ return [value, nil]
103
+ end
89
104
  end
90
105
  end
@@ -0,0 +1,8 @@
1
+ class OpenAPIParser::SchemaValidator
2
+ class UnspecifiedTypeValidator < Base
3
+ # @param [Object] value
4
+ def coerce_and_validate(value, _schema, **_keyword_args)
5
+ value
6
+ end
7
+ end
8
+ end
@@ -3,8 +3,6 @@
3
3
 
4
4
  module OpenAPIParser::Schemas
5
5
  class PathItem < Base
6
- include OpenAPIParser::ParameterValidatable
7
-
8
6
  openapi_attr_values :summary, :description
9
7
 
10
8
  openapi_attr_objects :get, :put, :post, :delete, :options, :head, :patch, :trace, Operation
@@ -16,5 +14,9 @@ module OpenAPIParser::Schemas
16
14
  rescue NoMethodError
17
15
  nil
18
16
  end
17
+
18
+ def set_path_item_to_operation
19
+ [:get, :put, :post, :delete, :options, :head, :patch, :trace].each{ |method| operation(method)&.set_parent_path_item(self)}
20
+ end
19
21
  end
20
22
  end
@@ -1,3 +1,3 @@
1
1
  module OpenAPIParser
2
- VERSION = '0.12.1'.freeze
2
+ VERSION = '0.15.0'.freeze
3
3
  end
@@ -93,6 +93,11 @@ module OpenAPIParser
93
93
 
94
94
  OpenAPIParser::ReferenceExpander.expand(root) if config.expand_reference
95
95
 
96
+ # TODO: use callbacks
97
+ root.paths&.path&.values&.each do | path_item |
98
+ path_item.set_path_item_to_operation
99
+ end
100
+
96
101
  root
97
102
  end
98
103
  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.12.1
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ota42y
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-27 00:00:00.000000000 Z
11
+ date: 2021-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -129,17 +129,18 @@ executables: []
129
129
  extensions: []
130
130
  extra_rdoc_files: []
131
131
  files:
132
+ - ".github/workflows/ci.yaml"
132
133
  - ".gitignore"
133
134
  - ".rspec"
134
135
  - ".rubocop.yml"
135
136
  - ".rubocop_ignore.yml"
136
- - ".travis.yml"
137
137
  - CHANGELOG.md
138
138
  - CODE_OF_CONDUCT.md
139
139
  - Gemfile
140
140
  - LICENSE.txt
141
141
  - README.md
142
142
  - Rakefile
143
+ - TAGS
143
144
  - bin/console
144
145
  - bin/setup
145
146
  - lib/openapi_parser.rb
@@ -184,6 +185,7 @@ files:
184
185
  - lib/openapi_parser/schema_validators/one_of_validator.rb
185
186
  - lib/openapi_parser/schema_validators/options.rb
186
187
  - lib/openapi_parser/schema_validators/string_validator.rb
188
+ - lib/openapi_parser/schema_validators/unspecified_type_validator.rb
187
189
  - lib/openapi_parser/schemas.rb
188
190
  - lib/openapi_parser/schemas/base.rb
189
191
  - lib/openapi_parser/schemas/classes.rb
@@ -207,7 +209,7 @@ homepage: https://github.com/ota42y/openapi_parser
207
209
  licenses:
208
210
  - MIT
209
211
  metadata: {}
210
- post_install_message:
212
+ post_install_message:
211
213
  rdoc_options: []
212
214
  require_paths:
213
215
  - lib
@@ -222,8 +224,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
224
  - !ruby/object:Gem::Version
223
225
  version: '0'
224
226
  requirements: []
225
- rubygems_version: 3.1.2
226
- signing_key:
227
+ rubygems_version: 3.2.3
228
+ signing_key:
227
229
  specification_version: 4
228
230
  summary: OpenAPI3 parser
229
231
  test_files: []
data/.travis.yml DELETED
@@ -1,37 +0,0 @@
1
- env:
2
- global:
3
- - CC_TEST_REPORTER_ID=b49a1717b8ff0aef9eced41d0f87d350a88b46d55083ba2e3df8b6f441ae3fb7
4
-
5
- language: ruby
6
-
7
- rvm:
8
- - 2.3.8
9
- - 2.4.10
10
- - 2.5.8
11
- - 2.6.6
12
- - 2.7.1
13
- - ruby-head
14
-
15
- cache: bundler
16
-
17
- before_script:
18
- - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
19
- - chmod +x ./cc-test-reporter
20
- - ./cc-test-reporter before-build
21
-
22
- script: bundle exec rspec
23
-
24
- after_script:
25
- - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
26
-
27
- notifications:
28
- email: false
29
-
30
- sudo: false
31
-
32
- git:
33
- depth: 10
34
-
35
- matrix:
36
- allow_failures:
37
- - rvm: ruby-head