openapi_first 1.0.0.beta1 → 1.0.0.beta4

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +8 -20
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +23 -0
  5. data/Gemfile +4 -1
  6. data/Gemfile.lock +39 -51
  7. data/README.md +27 -25
  8. data/benchmarks/Gemfile.lock +28 -33
  9. data/benchmarks/apps/openapi_first_with_hanami_api.ru +1 -2
  10. data/benchmarks/apps/openapi_first_with_plain_rack.ru +32 -0
  11. data/benchmarks/apps/openapi_first_with_response_validation.ru +14 -11
  12. data/benchmarks/apps/openapi_first_with_sinatra.ru +29 -0
  13. data/lib/openapi_first/body_parser_middleware.rb +1 -1
  14. data/lib/openapi_first/config.rb +19 -0
  15. data/lib/openapi_first/default_error_response.rb +47 -0
  16. data/lib/openapi_first/definition.rb +8 -1
  17. data/lib/openapi_first/error_response.rb +31 -0
  18. data/lib/openapi_first/errors.rb +3 -40
  19. data/lib/openapi_first/operation.rb +33 -14
  20. data/lib/openapi_first/operation_schemas.rb +52 -0
  21. data/lib/openapi_first/plugins.rb +17 -0
  22. data/lib/openapi_first/request_body_validator.rb +41 -0
  23. data/lib/openapi_first/request_validation.rb +66 -84
  24. data/lib/openapi_first/response_validation.rb +38 -7
  25. data/lib/openapi_first/response_validator.rb +1 -1
  26. data/lib/openapi_first/router.rb +15 -14
  27. data/lib/openapi_first/schema_validation.rb +22 -21
  28. data/lib/openapi_first/string_keyed_hash.rb +20 -0
  29. data/lib/openapi_first/validation_result.rb +15 -0
  30. data/lib/openapi_first/version.rb +1 -1
  31. data/lib/openapi_first.rb +30 -21
  32. data/openapi_first.gemspec +4 -12
  33. metadata +20 -117
  34. data/benchmarks/apps/openapi_first.ru +0 -22
  35. data/lib/openapi_first/utils.rb +0 -35
  36. data/lib/openapi_first/validation_format.rb +0 -55
  37. /data/benchmarks/apps/{committee.ru → committee_with_hanami_api.ru} +0 -0
@@ -7,6 +7,9 @@ require_relative 'body_parser_middleware'
7
7
 
8
8
  module OpenapiFirst
9
9
  class Router
10
+ # The unconverted path parameters before they are converted to the types defined in the API description
11
+ RAW_PATH_PARAMS = 'openapi.raw_path_params'
12
+
10
13
  def initialize(
11
14
  app,
12
15
  options
@@ -63,17 +66,16 @@ module OpenapiFirst
63
66
  env[Rack::PATH_INFO] = env.delete(ORIGINAL_PATH) if env[ORIGINAL_PATH]
64
67
  end
65
68
 
66
- def handle_body_parsing_error(exception)
67
- err = { title: 'Failed to parse body as application/json', status: '400' }
68
- err[:detail] = exception.cause unless ENV['RACK_ENV'] == 'production'
69
- errors = [err]
70
- raise RequestInvalidError, errors if @raise
71
-
72
- Rack::Response.new(
73
- MultiJson.dump(errors: errors),
74
- 400,
75
- Rack::CONTENT_TYPE => 'application/vnd.api+json'
76
- ).finish
69
+ def handle_body_parsing_error(_exception)
70
+ message = 'Failed to parse body as application/json'
71
+ raise RequestInvalidError, message if @raise
72
+
73
+ error = {
74
+ status: 400,
75
+ title: message
76
+ }
77
+
78
+ ErrorResponse::Default.new(**error).finish
77
79
  end
78
80
 
79
81
  def build_router(operations)
@@ -89,7 +91,7 @@ module OpenapiFirst
89
91
  end
90
92
  raise_error = @raise
91
93
  Rack::Builder.app do
92
- use BodyParserMiddleware, raise_error: raise_error
94
+ use(BodyParserMiddleware, raise_error:)
93
95
  run router
94
96
  end
95
97
  end
@@ -99,8 +101,7 @@ module OpenapiFirst
99
101
  env[OPERATION] = operation
100
102
  path_info = env.delete(ORIGINAL_PATH)
101
103
  env[REQUEST_BODY] = env.delete(ROUTER_PARSED_BODY) if env.key?(ROUTER_PARSED_BODY)
102
- route_params = Utils::StringKeyedHash.new(env['router.params'])
103
- env[PARAMS] = OpenapiParameters::Path.new(operation.path_parameters).unpack(route_params)
104
+ env[RAW_PATH_PARAMS] = env['router.params']
104
105
  env[Rack::PATH_INFO] = path_info
105
106
  @app.call(env)
106
107
  end
@@ -1,46 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json_schemer'
4
+ require_relative 'validation_result'
4
5
 
5
6
  module OpenapiFirst
6
7
  class SchemaValidation
7
8
  attr_reader :raw_schema
8
9
 
9
- def initialize(schema, write: true)
10
+ SCHEMAS = {
11
+ '3.1' => 'https://spec.openapis.org/oas/3.1/dialect/base',
12
+ '3.0' => 'json-schemer://openapi30/schema'
13
+ }.freeze
14
+
15
+ def initialize(schema, openapi_version:, write: true)
10
16
  @raw_schema = schema
11
- custom_keywords = {}
12
- custom_keywords['writeOnly'] = proc { |data| !data } unless write
13
- custom_keywords['readOnly'] = proc { |data| !data } if write
14
17
  @schemer = JSONSchemer.schema(
15
18
  schema,
16
- keywords: custom_keywords,
19
+ access_mode: write ? 'write' : 'read',
20
+ meta_schema: SCHEMAS.fetch(openapi_version),
17
21
  insert_property_defaults: true,
18
- before_property_validation: proc do |data, property, property_schema, parent|
19
- convert_nullable(data, property, property_schema, parent)
20
- binary_format(data, property, property_schema, parent)
21
- end
22
+ output_format: 'detailed',
23
+ before_property_validation: method(:before_property_validation)
22
24
  )
23
25
  end
24
26
 
25
- def validate(input)
26
- @schemer.validate(input)
27
+ def validate(data)
28
+ ValidationResult.new(
29
+ output: @schemer.validate(data),
30
+ schema: raw_schema,
31
+ data:
32
+ )
27
33
  end
28
34
 
29
35
  private
30
36
 
31
- def binary_format(data, property, property_schema, _parent)
32
- return unless property_schema.is_a?(Hash) && property_schema['format'] == 'binary'
33
-
34
- property_schema['type'] = 'object'
35
- property_schema.delete('format')
36
- data[property].transform_keys!(&:to_s)
37
+ def before_property_validation(data, property, property_schema, parent)
38
+ binary_format(data, property, property_schema, parent)
37
39
  end
38
40
 
39
- def convert_nullable(_data, _property, property_schema, _parent)
40
- return unless property_schema.is_a?(Hash) && property_schema['nullable'] && property_schema['type']
41
+ def binary_format(data, property, property_schema, _parent)
42
+ return unless property_schema.is_a?(Hash) && property_schema['format'] == 'binary'
41
43
 
42
- property_schema['type'] = [*property_schema['type'], 'null']
43
- property_schema.delete('nullable')
44
+ data[property] = data[property][:tempfile].read
44
45
  end
45
46
  end
46
47
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ class StringKeyedHash
5
+ extend Forwardable
6
+ def_delegators :@orig, :empty?
7
+
8
+ def initialize(original)
9
+ @orig = original
10
+ end
11
+
12
+ def key?(key)
13
+ @orig.key?(key.to_sym)
14
+ end
15
+
16
+ def [](key)
17
+ @orig[key.to_sym]
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ ValidationResult = Struct.new(:output, :schema, :data, keyword_init: true) do
5
+ def valid? = output['valid']
6
+ def error? = !output['valid']
7
+
8
+ # Returns a message that is used in exception messages.
9
+ def message
10
+ return if valid?
11
+
12
+ (output['errors']&.map { |e| e['error'] }&.join('. ') || output['error'])&.concat('.')
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiFirst
4
- VERSION = '1.0.0.beta1'
4
+ VERSION = '1.0.0.beta4'
5
5
  end
data/lib/openapi_first.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'yaml'
4
4
  require 'json_refs'
5
+ require_relative 'openapi_first/config'
6
+ require_relative 'openapi_first/plugins'
5
7
  require_relative 'openapi_first/definition'
6
8
  require_relative 'openapi_first/version'
7
9
  require_relative 'openapi_first/errors'
@@ -9,15 +11,40 @@ require_relative 'openapi_first/router'
9
11
  require_relative 'openapi_first/request_validation'
10
12
  require_relative 'openapi_first/response_validator'
11
13
  require_relative 'openapi_first/response_validation'
14
+ require_relative 'openapi_first/default_error_response'
12
15
 
13
16
  module OpenapiFirst
17
+ # The OpenAPI operation for the current request
14
18
  OPERATION = 'openapi.operation'
19
+
20
+ # Merged parsed path and query parameters
15
21
  PARAMS = 'openapi.params'
22
+
23
+ # Parsed query parameters
24
+ QUERY_PARAMS = 'openapi.query'
25
+
26
+ # Parsed path parameters
27
+ PATH_PARAMS = 'openapi.path_params'
28
+
29
+ # Parsed header parameters, except for Content-Type, Accept and Authorization
30
+ HEADER_PARAMS = 'openapi.headers'
31
+
32
+ # Parsed cookie parameter values
33
+ COOKIE_PARAMS = 'openapi.cookies'
34
+
35
+ # The parsed request body
16
36
  REQUEST_BODY = 'openapi.parsed_request_body'
17
- HANDLER = 'openapi_first.handler'
18
37
 
19
- def self.env
20
- ENV['RACK_ENV'] || ENV['HANAMI_ENV'] || ENV.fetch('RAILS_ENV', nil)
38
+ class << self
39
+ # Throws an error in the middle of the request validation to stop validation and send a response.
40
+ def error!(status, location = nil, title: nil, validation_result: nil)
41
+ throw :error, {
42
+ status:,
43
+ location:,
44
+ title: title || validation_result&.output&.fetch('error') || Rack::Utils::HTTP_STATUS_CODES[status],
45
+ validation_result:
46
+ }
47
+ end
21
48
  end
22
49
 
23
50
  def self.load(spec_path, only: nil)
@@ -28,22 +55,4 @@ module OpenapiFirst
28
55
  resolved['paths'].filter!(&->(key, _) { only.call(key) }) if only
29
56
  Definition.new(resolved, spec_path)
30
57
  end
31
-
32
- def self.app(
33
- spec,
34
- namespace:,
35
- router_raise_error: false,
36
- request_validation_raise_error: false,
37
- response_validation: false
38
- )
39
- spec = OpenapiFirst.load(spec) unless spec.is_a?(Definition)
40
- App.new(
41
- nil,
42
- spec,
43
- namespace: namespace,
44
- router_raise_error: router_raise_error,
45
- request_validation_raise_error: request_validation_raise_error,
46
- response_validation: response_validation
47
- )
48
- end
49
58
  end
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.email = ['andreas.haller@posteo.de']
12
12
  spec.licenses = ['MIT']
13
13
 
14
- spec.summary = 'Implement REST APIs based on OpenApi.'
14
+ spec.summary = 'Implement REST APIs based on OpenApi 3.x'
15
15
  spec.homepage = 'https://github.com/ahx/openapi_first'
16
16
 
17
17
  if spec.respond_to?(:metadata)
@@ -32,22 +32,14 @@ Gem::Specification.new do |spec|
32
32
  spec.bindir = 'exe'
33
33
  spec.require_paths = ['lib']
34
34
 
35
- spec.required_ruby_version = '>= 3.0.5'
35
+ spec.required_ruby_version = '>= 3.1.1'
36
36
 
37
- spec.add_runtime_dependency 'deep_merge', '>= 1.2.1'
38
37
  spec.add_runtime_dependency 'hanami-router', '~> 2.0.0'
39
- spec.add_runtime_dependency 'hanami-utils', '~> 2.0.0'
40
38
  spec.add_runtime_dependency 'json_refs', '~> 0.1', '>= 0.1.7'
41
- spec.add_runtime_dependency 'json_schemer', '~> 0.2.16'
39
+ spec.add_runtime_dependency 'json_schemer', '~> 2.0.0'
42
40
  spec.add_runtime_dependency 'multi_json', '~> 1.14'
43
- spec.add_runtime_dependency 'mustermann-contrib', '~> 3.0.0'
41
+ spec.add_runtime_dependency 'openapi_parameters', '~> 0.2.2'
44
42
  spec.add_runtime_dependency 'rack', '>= 2.2', '< 4.0'
45
-
46
- spec.add_development_dependency 'bundler', '~> 2'
47
- spec.add_development_dependency 'openapi_parameters', '~> 0.2', '<= 2.0.0'
48
- spec.add_development_dependency 'rack-test', '~> 1'
49
- spec.add_development_dependency 'rake', '~> 13'
50
- spec.add_development_dependency 'rspec', '~> 3'
51
43
  spec.metadata = {
52
44
  'rubygems_mfa_required' => 'true'
53
45
  }
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_first
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta1
4
+ version: 1.0.0.beta4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Haller
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-17 00:00:00.000000000 Z
11
+ date: 2023-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: deep_merge
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 1.2.1
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: 1.2.1
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: hanami-router
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -38,20 +24,6 @@ dependencies:
38
24
  - - "~>"
39
25
  - !ruby/object:Gem::Version
40
26
  version: 2.0.0
41
- - !ruby/object:Gem::Dependency
42
- name: hanami-utils
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 2.0.0
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 2.0.0
55
27
  - !ruby/object:Gem::Dependency
56
28
  name: json_refs
57
29
  requirement: !ruby/object:Gem::Requirement
@@ -78,14 +50,14 @@ dependencies:
78
50
  requirements:
79
51
  - - "~>"
80
52
  - !ruby/object:Gem::Version
81
- version: 0.2.16
53
+ version: 2.0.0
82
54
  type: :runtime
83
55
  prerelease: false
84
56
  version_requirements: !ruby/object:Gem::Requirement
85
57
  requirements:
86
58
  - - "~>"
87
59
  - !ruby/object:Gem::Version
88
- version: 0.2.16
60
+ version: 2.0.0
89
61
  - !ruby/object:Gem::Dependency
90
62
  name: multi_json
91
63
  requirement: !ruby/object:Gem::Requirement
@@ -101,19 +73,19 @@ dependencies:
101
73
  - !ruby/object:Gem::Version
102
74
  version: '1.14'
103
75
  - !ruby/object:Gem::Dependency
104
- name: mustermann-contrib
76
+ name: openapi_parameters
105
77
  requirement: !ruby/object:Gem::Requirement
106
78
  requirements:
107
79
  - - "~>"
108
80
  - !ruby/object:Gem::Version
109
- version: 3.0.0
81
+ version: 0.2.2
110
82
  type: :runtime
111
83
  prerelease: false
112
84
  version_requirements: !ruby/object:Gem::Requirement
113
85
  requirements:
114
86
  - - "~>"
115
87
  - !ruby/object:Gem::Version
116
- version: 3.0.0
88
+ version: 0.2.2
117
89
  - !ruby/object:Gem::Dependency
118
90
  name: rack
119
91
  requirement: !ruby/object:Gem::Requirement
@@ -134,82 +106,6 @@ dependencies:
134
106
  - - "<"
135
107
  - !ruby/object:Gem::Version
136
108
  version: '4.0'
137
- - !ruby/object:Gem::Dependency
138
- name: bundler
139
- requirement: !ruby/object:Gem::Requirement
140
- requirements:
141
- - - "~>"
142
- - !ruby/object:Gem::Version
143
- version: '2'
144
- type: :development
145
- prerelease: false
146
- version_requirements: !ruby/object:Gem::Requirement
147
- requirements:
148
- - - "~>"
149
- - !ruby/object:Gem::Version
150
- version: '2'
151
- - !ruby/object:Gem::Dependency
152
- name: openapi_parameters
153
- requirement: !ruby/object:Gem::Requirement
154
- requirements:
155
- - - "~>"
156
- - !ruby/object:Gem::Version
157
- version: '0.2'
158
- - - "<="
159
- - !ruby/object:Gem::Version
160
- version: 2.0.0
161
- type: :development
162
- prerelease: false
163
- version_requirements: !ruby/object:Gem::Requirement
164
- requirements:
165
- - - "~>"
166
- - !ruby/object:Gem::Version
167
- version: '0.2'
168
- - - "<="
169
- - !ruby/object:Gem::Version
170
- version: 2.0.0
171
- - !ruby/object:Gem::Dependency
172
- name: rack-test
173
- requirement: !ruby/object:Gem::Requirement
174
- requirements:
175
- - - "~>"
176
- - !ruby/object:Gem::Version
177
- version: '1'
178
- type: :development
179
- prerelease: false
180
- version_requirements: !ruby/object:Gem::Requirement
181
- requirements:
182
- - - "~>"
183
- - !ruby/object:Gem::Version
184
- version: '1'
185
- - !ruby/object:Gem::Dependency
186
- name: rake
187
- requirement: !ruby/object:Gem::Requirement
188
- requirements:
189
- - - "~>"
190
- - !ruby/object:Gem::Version
191
- version: '13'
192
- type: :development
193
- prerelease: false
194
- version_requirements: !ruby/object:Gem::Requirement
195
- requirements:
196
- - - "~>"
197
- - !ruby/object:Gem::Version
198
- version: '13'
199
- - !ruby/object:Gem::Dependency
200
- name: rspec
201
- requirement: !ruby/object:Gem::Requirement
202
- requirements:
203
- - - "~>"
204
- - !ruby/object:Gem::Version
205
- version: '3'
206
- type: :development
207
- prerelease: false
208
- version_requirements: !ruby/object:Gem::Requirement
209
- requirements:
210
- - - "~>"
211
- - !ruby/object:Gem::Version
212
- version: '3'
213
109
  description:
214
110
  email:
215
111
  - andreas.haller@posteo.de
@@ -231,16 +127,17 @@ files:
231
127
  - benchmarks/Gemfile
232
128
  - benchmarks/Gemfile.lock
233
129
  - benchmarks/README.md
234
- - benchmarks/apps/committee.ru
130
+ - benchmarks/apps/committee_with_hanami_api.ru
235
131
  - benchmarks/apps/committee_with_response_validation.ru
236
132
  - benchmarks/apps/committee_with_sinatra.ru
237
133
  - benchmarks/apps/grape.ru
238
134
  - benchmarks/apps/hanami_api.ru
239
135
  - benchmarks/apps/hanami_router.ru
240
136
  - benchmarks/apps/openapi.yaml
241
- - benchmarks/apps/openapi_first.ru
242
137
  - benchmarks/apps/openapi_first_with_hanami_api.ru
138
+ - benchmarks/apps/openapi_first_with_plain_rack.ru
243
139
  - benchmarks/apps/openapi_first_with_response_validation.ru
140
+ - benchmarks/apps/openapi_first_with_sinatra.ru
244
141
  - benchmarks/apps/roda.ru
245
142
  - benchmarks/apps/sinatra.ru
246
143
  - benchmarks/apps/syro.ru
@@ -255,17 +152,23 @@ files:
255
152
  - examples/openapi.yaml
256
153
  - lib/openapi_first.rb
257
154
  - lib/openapi_first/body_parser_middleware.rb
155
+ - lib/openapi_first/config.rb
156
+ - lib/openapi_first/default_error_response.rb
258
157
  - lib/openapi_first/definition.rb
158
+ - lib/openapi_first/error_response.rb
259
159
  - lib/openapi_first/errors.rb
260
160
  - lib/openapi_first/operation.rb
161
+ - lib/openapi_first/operation_schemas.rb
162
+ - lib/openapi_first/plugins.rb
163
+ - lib/openapi_first/request_body_validator.rb
261
164
  - lib/openapi_first/request_validation.rb
262
165
  - lib/openapi_first/response_validation.rb
263
166
  - lib/openapi_first/response_validator.rb
264
167
  - lib/openapi_first/router.rb
265
168
  - lib/openapi_first/schema_validation.rb
169
+ - lib/openapi_first/string_keyed_hash.rb
266
170
  - lib/openapi_first/use_router.rb
267
- - lib/openapi_first/utils.rb
268
- - lib/openapi_first/validation_format.rb
171
+ - lib/openapi_first/validation_result.rb
269
172
  - lib/openapi_first/version.rb
270
173
  - openapi_first.gemspec
271
174
  homepage: https://github.com/ahx/openapi_first
@@ -281,7 +184,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
281
184
  requirements:
282
185
  - - ">="
283
186
  - !ruby/object:Gem::Version
284
- version: 3.0.5
187
+ version: 3.1.1
285
188
  required_rubygems_version: !ruby/object:Gem::Requirement
286
189
  requirements:
287
190
  - - ">"
@@ -291,5 +194,5 @@ requirements: []
291
194
  rubygems_version: 3.3.7
292
195
  signing_key:
293
196
  specification_version: 4
294
- summary: Implement REST APIs based on OpenApi.
197
+ summary: Implement REST APIs based on OpenApi 3.x
295
198
  test_files: []
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'multi_json'
4
- require 'openapi_first'
5
-
6
- namespace = Module.new do
7
- def self.find_thing(params, _res)
8
- { hello: 'world', id: params.fetch('id') }
9
- end
10
-
11
- def self.find_things(_params, _res)
12
- [{ hello: 'world' }]
13
- end
14
-
15
- def self.create_thing(_params, res)
16
- res.status = 201
17
- { hello: 'world' }
18
- end
19
- end
20
-
21
- oas_path = File.absolute_path('./openapi.yaml', __dir__)
22
- run OpenapiFirst.app(oas_path, namespace: namespace)
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'hanami/utils/string'
4
- require 'hanami/utils/hash'
5
- require 'deep_merge/core'
6
-
7
- module OpenapiFirst
8
- module Utils
9
- def self.deep_merge!(dest, source)
10
- DeepMerge.deep_merge!(source, dest)
11
- end
12
-
13
- def self.underscore(string)
14
- Hanami::Utils::String.underscore(string)
15
- end
16
-
17
- def self.classify(string)
18
- Hanami::Utils::String.classify(string)
19
- end
20
-
21
- class StringKeyedHash
22
- def initialize(original)
23
- @orig = original
24
- end
25
-
26
- def key?(key)
27
- @orig.key?(key.to_sym)
28
- end
29
-
30
- def [](key)
31
- @orig[key.to_sym]
32
- end
33
- end
34
- end
35
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- module ValidationFormat
5
- SIMPLE_TYPES = %w[string integer].freeze
6
-
7
- # rubocop:disable Metrics/MethodLength
8
- # rubocop:disable Metrics/AbcSize
9
- # rubocop:disable Metrics/CyclomaticComplexity
10
- # rubocop:disable Metrics/PerceivedComplexity
11
- def self.error_details(error)
12
- if error['type'] == 'pattern'
13
- {
14
- title: 'is not valid',
15
- detail: "does not match pattern '#{error['schema']['pattern']}'"
16
- }
17
- elsif error['type'] == 'format'
18
- {
19
- title: "has not a valid #{error.dig('schema', 'format')} format",
20
- detail: "#{error['data'].inspect} is not a valid #{error.dig('schema', 'format')} format"
21
- }
22
- elsif error['type'] == 'enum'
23
- {
24
- title: "value #{error['data'].inspect} is not defined in enum",
25
- detail: "value can be one of #{error.dig('schema', 'enum')&.join(', ')}"
26
- }
27
- elsif error['type'] == 'required'
28
- missing_keys = error['details']['missing_keys']
29
- {
30
- title: "is missing required properties: #{missing_keys.join(', ')}"
31
- }
32
- elsif error['type'] == 'readOnly'
33
- {
34
- title: 'appears in request, but is read-only'
35
- }
36
- elsif error['type'] == 'writeOnly'
37
- {
38
- title: 'write-only field appears in response:'
39
- }
40
- elsif SIMPLE_TYPES.include?(error['type'])
41
- {
42
- title: "should be a #{error['type']}"
43
- }
44
- elsif error['schema'] == false
45
- { title: 'unknown fields are not allowed' }
46
- else
47
- { title: "is not valid: #{error['data'].inspect}" }
48
- end
49
- end
50
- # rubocop:enable Metrics/MethodLength
51
- # rubocop:enable Metrics/AbcSize
52
- # rubocop:enable Metrics/CyclomaticComplexity
53
- # rubocop:enable Metrics/PerceivedComplexity
54
- end
55
- end