openapi_first 1.0.0.beta6 → 1.0.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -3
  3. data/Gemfile +1 -0
  4. data/Gemfile.lock +11 -10
  5. data/Gemfile.rack2.lock +99 -0
  6. data/README.md +99 -130
  7. data/lib/openapi_first/body_parser.rb +5 -4
  8. data/lib/openapi_first/configuration.rb +20 -0
  9. data/lib/openapi_first/definition/operation.rb +84 -71
  10. data/lib/openapi_first/definition/parameters.rb +1 -1
  11. data/lib/openapi_first/definition/path_item.rb +21 -12
  12. data/lib/openapi_first/definition/path_parameters.rb +2 -3
  13. data/lib/openapi_first/definition/request_body.rb +22 -11
  14. data/lib/openapi_first/definition/response.rb +19 -31
  15. data/lib/openapi_first/definition/responses.rb +83 -0
  16. data/lib/openapi_first/definition.rb +50 -17
  17. data/lib/openapi_first/error_response.rb +22 -29
  18. data/lib/openapi_first/errors.rb +2 -14
  19. data/lib/openapi_first/failure.rb +55 -0
  20. data/lib/openapi_first/middlewares/request_validation.rb +52 -0
  21. data/lib/openapi_first/middlewares/response_validation.rb +35 -0
  22. data/lib/openapi_first/plugins/default/error_response.rb +74 -0
  23. data/lib/openapi_first/plugins/default.rb +11 -0
  24. data/lib/openapi_first/plugins/jsonapi/error_response.rb +58 -0
  25. data/lib/openapi_first/plugins/jsonapi.rb +11 -0
  26. data/lib/openapi_first/plugins.rb +9 -7
  27. data/lib/openapi_first/request_validation/request_body_validator.rb +41 -0
  28. data/lib/openapi_first/request_validation/validator.rb +81 -0
  29. data/lib/openapi_first/response_validation/validator.rb +101 -0
  30. data/lib/openapi_first/runtime_request.rb +84 -0
  31. data/lib/openapi_first/runtime_response.rb +31 -0
  32. data/lib/openapi_first/schema/validation_error.rb +18 -0
  33. data/lib/openapi_first/schema/validation_result.rb +32 -0
  34. data/lib/openapi_first/{definition/schema.rb → schema.rb} +8 -4
  35. data/lib/openapi_first/version.rb +1 -1
  36. data/lib/openapi_first.rb +32 -28
  37. data/openapi_first.gemspec +3 -5
  38. metadata +28 -20
  39. data/lib/openapi_first/config.rb +0 -20
  40. data/lib/openapi_first/definition/has_content.rb +0 -37
  41. data/lib/openapi_first/definition/schema/result.rb +0 -17
  42. data/lib/openapi_first/error_responses/default.rb +0 -58
  43. data/lib/openapi_first/error_responses/json_api.rb +0 -58
  44. data/lib/openapi_first/request_body_validator.rb +0 -37
  45. data/lib/openapi_first/request_validation.rb +0 -122
  46. data/lib/openapi_first/request_validation_error.rb +0 -31
  47. data/lib/openapi_first/response_validation.rb +0 -113
  48. data/lib/openapi_first/response_validator.rb +0 -21
  49. data/lib/openapi_first/router.rb +0 -68
  50. data/lib/openapi_first/use_router.rb +0 -18
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'validation_error'
4
+
5
+ module OpenapiFirst
6
+ class Schema
7
+ class ValidationResult
8
+ def initialize(validation, schema:, data:)
9
+ @validation = validation
10
+ @schema = schema
11
+ @data = data
12
+ end
13
+
14
+ attr_reader :schema, :data
15
+
16
+ def error? = @validation.any?
17
+
18
+ def errors
19
+ @errors ||= @validation.map do |err|
20
+ ValidationError.new(err)
21
+ end
22
+ end
23
+
24
+ # Returns a message that is used in exception messages.
25
+ def message
26
+ return unless error?
27
+
28
+ errors.map(&:error).join('. ')
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json_schemer'
4
- require_relative 'schema/result'
4
+ require_relative 'schema/validation_result'
5
5
 
6
6
  module OpenapiFirst
7
7
  class Schema
@@ -19,19 +19,23 @@ module OpenapiFirst
19
19
  access_mode: write ? 'write' : 'read',
20
20
  meta_schema: SCHEMAS.fetch(openapi_version),
21
21
  insert_property_defaults: true,
22
- output_format: 'detailed',
22
+ output_format: 'classic',
23
23
  before_property_validation: method(:before_property_validation)
24
24
  )
25
25
  end
26
26
 
27
27
  def validate(data)
28
- Result.new(
29
- output: @schemer.validate(data),
28
+ ValidationResult.new(
29
+ @schemer.validate(data),
30
30
  schema:,
31
31
  data:
32
32
  )
33
33
  end
34
34
 
35
+ def [](key)
36
+ @schema[key]
37
+ end
38
+
35
39
  private
36
40
 
37
41
  def before_property_validation(data, property, property_schema, parent)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiFirst
4
- VERSION = '1.0.0.beta6'
4
+ VERSION = '1.0.0'
5
5
  end
data/lib/openapi_first.rb CHANGED
@@ -1,47 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'yaml'
4
+ require 'multi_json'
4
5
  require 'json_refs'
5
- require_relative 'openapi_first/config'
6
+ require_relative 'openapi_first/errors'
7
+ require_relative 'openapi_first/configuration'
6
8
  require_relative 'openapi_first/plugins'
7
9
  require_relative 'openapi_first/definition'
8
10
  require_relative 'openapi_first/version'
9
- require_relative 'openapi_first/errors'
10
- require_relative 'openapi_first/router'
11
- require_relative 'openapi_first/request_validation'
12
- require_relative 'openapi_first/response_validator'
13
- require_relative 'openapi_first/response_validation'
14
- require_relative 'openapi_first/error_responses/default'
15
- require_relative 'openapi_first/error_responses/json_api'
11
+ require_relative 'openapi_first/error_response'
12
+ require_relative 'openapi_first/middlewares/response_validation'
13
+ require_relative 'openapi_first/middlewares/request_validation'
16
14
 
17
15
  module OpenapiFirst
18
- # The OpenAPI operation for the current request
19
- OPERATION = 'openapi.operation'
16
+ extend Plugins
20
17
 
21
- # Merged parsed path and query parameters
22
- PARAMS = 'openapi.params'
18
+ class << self
19
+ def configuration
20
+ @configuration ||= Configuration.new
21
+ end
23
22
 
24
- # Parsed query parameters
25
- QUERY_PARAMS = 'openapi.query'
23
+ def configure
24
+ yield configuration
25
+ end
26
+ end
26
27
 
27
- # Parsed path parameters
28
- PATH_PARAMS = 'openapi.path_params'
28
+ # Key in rack to find instance of RuntimeRequest
29
+ REQUEST = 'openapi.request'
29
30
 
30
- # Parsed header parameters, except for Content-Type, Accept and Authorization
31
- HEADER_PARAMS = 'openapi.headers'
31
+ def self.load(spec_path, only: nil)
32
+ resolved = Bundle.resolve(spec_path)
33
+ resolved['paths'].filter!(&->(key, _) { only.call(key) }) if only
34
+ Definition.new(resolved, spec_path)
35
+ end
32
36
 
33
- # Parsed cookie parameter values
34
- COOKIE_PARAMS = 'openapi.cookies'
37
+ module Bundle
38
+ def self.resolve(spec_path)
39
+ Dir.chdir(File.dirname(spec_path)) do
40
+ content = load_file(File.basename(spec_path))
41
+ JsonRefs.call(content, resolve_local_ref: true, resolve_file_ref: true)
42
+ end
43
+ end
35
44
 
36
- # The parsed request body
37
- REQUEST_BODY = 'openapi.parsed_request_body'
45
+ def self.load_file(spec_path)
46
+ return MultiJson.load(File.read(spec_path)) if File.extname(spec_path) == '.json'
38
47
 
39
- def self.load(spec_path, only: nil)
40
- resolved = Dir.chdir(File.dirname(spec_path)) do
41
- content = YAML.load_file(File.basename(spec_path))
42
- JsonRefs.call(content, resolve_local_ref: true, resolve_file_ref: true)
48
+ YAML.unsafe_load_file(spec_path)
43
49
  end
44
- resolved['paths'].filter!(&->(key, _) { only.call(key) }) if only
45
- Definition.new(resolved, spec_path)
46
50
  end
47
51
  end
@@ -17,7 +17,8 @@ Gem::Specification.new do |spec|
17
17
  if spec.respond_to?(:metadata)
18
18
  spec.metadata['https://github.com/ahx/openapi_first'] = spec.homepage
19
19
  spec.metadata['source_code_uri'] = 'https://github.com/ahx/openapi_first'
20
- spec.metadata['changelog_uri'] = 'https://github.com/ahx/openapi_first/blob/master/CHANGELOG.md'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/ahx/openapi_first/blob/main/CHANGELOG.md'
21
+ spec.metadata['rubygems_mfa_required'] = 'true'
21
22
  else
22
23
  raise 'RubyGems 2.0 or newer is required to protect against ' \
23
24
  'public gem pushes.'
@@ -38,12 +39,9 @@ Gem::Specification.new do |spec|
38
39
  spec.required_ruby_version = '>= 3.1.1'
39
40
 
40
41
  spec.add_runtime_dependency 'json_refs', '~> 0.1', '>= 0.1.7'
41
- spec.add_runtime_dependency 'json_schemer', '~> 2.0.0'
42
+ spec.add_runtime_dependency 'json_schemer', '~> 2.1.0'
42
43
  spec.add_runtime_dependency 'multi_json', '~> 1.15'
43
44
  spec.add_runtime_dependency 'mustermann-contrib', '~> 3.0.0'
44
45
  spec.add_runtime_dependency 'openapi_parameters', '>= 0.3.2', '< 2.0'
45
46
  spec.add_runtime_dependency 'rack', '>= 2.2', '< 4.0'
46
- spec.metadata = {
47
- 'rubygems_mfa_required' => 'true'
48
- }
49
47
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_first
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta6
4
+ version: 1.0.0
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-11-16 00:00:00.000000000 Z
11
+ date: 2024-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json_refs
@@ -36,14 +36,14 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: 2.0.0
39
+ version: 2.1.0
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: 2.0.0
46
+ version: 2.1.0
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: multi_json
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -126,14 +126,14 @@ files:
126
126
  - Gemfile
127
127
  - Gemfile.lock
128
128
  - Gemfile.rack2
129
+ - Gemfile.rack2.lock
129
130
  - LICENSE.txt
130
131
  - README.md
131
132
  - lib/openapi_first.rb
132
133
  - lib/openapi_first/body_parser.rb
133
- - lib/openapi_first/config.rb
134
+ - lib/openapi_first/configuration.rb
134
135
  - lib/openapi_first/definition.rb
135
136
  - lib/openapi_first/definition/cookie_parameters.rb
136
- - lib/openapi_first/definition/has_content.rb
137
137
  - lib/openapi_first/definition/header_parameters.rb
138
138
  - lib/openapi_first/definition/operation.rb
139
139
  - lib/openapi_first/definition/parameters.rb
@@ -142,26 +142,34 @@ files:
142
142
  - lib/openapi_first/definition/query_parameters.rb
143
143
  - lib/openapi_first/definition/request_body.rb
144
144
  - lib/openapi_first/definition/response.rb
145
- - lib/openapi_first/definition/schema.rb
146
- - lib/openapi_first/definition/schema/result.rb
145
+ - lib/openapi_first/definition/responses.rb
147
146
  - lib/openapi_first/error_response.rb
148
- - lib/openapi_first/error_responses/default.rb
149
- - lib/openapi_first/error_responses/json_api.rb
150
147
  - lib/openapi_first/errors.rb
148
+ - lib/openapi_first/failure.rb
149
+ - lib/openapi_first/middlewares/request_validation.rb
150
+ - lib/openapi_first/middlewares/response_validation.rb
151
151
  - lib/openapi_first/plugins.rb
152
- - lib/openapi_first/request_body_validator.rb
153
- - lib/openapi_first/request_validation.rb
154
- - lib/openapi_first/request_validation_error.rb
155
- - lib/openapi_first/response_validation.rb
156
- - lib/openapi_first/response_validator.rb
157
- - lib/openapi_first/router.rb
158
- - lib/openapi_first/use_router.rb
152
+ - lib/openapi_first/plugins/default.rb
153
+ - lib/openapi_first/plugins/default/error_response.rb
154
+ - lib/openapi_first/plugins/jsonapi.rb
155
+ - lib/openapi_first/plugins/jsonapi/error_response.rb
156
+ - lib/openapi_first/request_validation/request_body_validator.rb
157
+ - lib/openapi_first/request_validation/validator.rb
158
+ - lib/openapi_first/response_validation/validator.rb
159
+ - lib/openapi_first/runtime_request.rb
160
+ - lib/openapi_first/runtime_response.rb
161
+ - lib/openapi_first/schema.rb
162
+ - lib/openapi_first/schema/validation_error.rb
163
+ - lib/openapi_first/schema/validation_result.rb
159
164
  - lib/openapi_first/version.rb
160
165
  - openapi_first.gemspec
161
166
  homepage: https://github.com/ahx/openapi_first
162
167
  licenses:
163
168
  - MIT
164
169
  metadata:
170
+ https://github.com/ahx/openapi_first: https://github.com/ahx/openapi_first
171
+ source_code_uri: https://github.com/ahx/openapi_first
172
+ changelog_uri: https://github.com/ahx/openapi_first/blob/main/CHANGELOG.md
165
173
  rubygems_mfa_required: 'true'
166
174
  post_install_message:
167
175
  rdoc_options: []
@@ -174,11 +182,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
174
182
  version: 3.1.1
175
183
  required_rubygems_version: !ruby/object:Gem::Requirement
176
184
  requirements:
177
- - - ">"
185
+ - - ">="
178
186
  - !ruby/object:Gem::Version
179
- version: 1.3.1
187
+ version: '0'
180
188
  requirements: []
181
- rubygems_version: 3.3.7
189
+ rubygems_version: 3.5.3
182
190
  signing_key:
183
191
  specification_version: 4
184
192
  summary: Implement REST APIs based on OpenApi 3.x
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- class Config
5
- def initialize(error_response: :default, request_validation_raise_error: false)
6
- @error_response = Plugins.find_error_response(error_response)
7
- @request_validation_raise_error = request_validation_raise_error
8
- end
9
-
10
- attr_reader :error_response, :request_validation_raise_error
11
-
12
- def self.default_options
13
- @default_options ||= new
14
- end
15
-
16
- def self.default_options=(options)
17
- @default_options = new(**options)
18
- end
19
- end
20
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'schema'
4
-
5
- module OpenapiFirst
6
- module HasContent
7
- def schema_for(content_type)
8
- return unless content&.any?
9
-
10
- content_schemas&.fetch(content_type) do
11
- type = content_type.split(';')[0]
12
- content_schemas[type] || content_schemas["#{type.split('/')[0]}/*"] || content_schemas['*/*']
13
- end
14
- end
15
-
16
- private
17
-
18
- def content
19
- raise NotImplementedError
20
- end
21
-
22
- def schema_write?
23
- raise NotImplementedError
24
- end
25
-
26
- def content_schemas
27
- @content_schemas ||= content&.each_with_object({}) do |kv, result|
28
- type, media_type = kv
29
- schema_object = media_type['schema']
30
- next unless schema_object
31
-
32
- result[type] = Schema.new(schema_object, write: schema_write?,
33
- openapi_version: @operation.openapi_version)
34
- end
35
- end
36
- end
37
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- class Schema
5
- Result = Struct.new(:output, :schema, :data, keyword_init: true) do
6
- def valid? = output['valid']
7
- def error? = !output['valid']
8
-
9
- # Returns a message that is used in exception messages.
10
- def message
11
- return if valid?
12
-
13
- (output['errors']&.map { |e| e['error'] }&.join('. ') || output['error'])
14
- end
15
- end
16
- end
17
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- module ErrorResponses
5
- class Default < ErrorResponse
6
- OpenapiFirst::Plugins.register_error_response(:default, self)
7
-
8
- def body
9
- MultiJson.dump({ errors: serialized_errors })
10
- end
11
-
12
- def content_type
13
- 'application/json'
14
- end
15
-
16
- def serialized_errors
17
- return default_errors unless validation_output
18
-
19
- key = pointer_key
20
- validation_errors&.map do |error|
21
- {
22
- status: status.to_s,
23
- source: { key => pointer(error['instanceLocation']) },
24
- title: error['error']
25
- }
26
- end
27
- end
28
-
29
- def validation_errors
30
- validation_output['errors'] || [validation_output]
31
- end
32
-
33
- def default_errors
34
- [{
35
- status: status.to_s,
36
- title: message
37
- }]
38
- end
39
-
40
- def pointer_key
41
- case location
42
- when :body
43
- :pointer
44
- when :query, :path
45
- :parameter
46
- else
47
- location
48
- end
49
- end
50
-
51
- def pointer(data_pointer)
52
- return data_pointer if location == :body
53
-
54
- data_pointer.delete_prefix('/')
55
- end
56
- end
57
- end
58
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- module ErrorResponses
5
- class JsonApi < ErrorResponse
6
- OpenapiFirst::Plugins.register_error_response(:json_api, self)
7
-
8
- def body
9
- MultiJson.dump({ errors: serialized_errors })
10
- end
11
-
12
- def content_type
13
- 'application/vnd.api+json'
14
- end
15
-
16
- def serialized_errors
17
- return default_errors unless validation_output
18
-
19
- key = pointer_key
20
- validation_errors&.map do |error|
21
- {
22
- status: status.to_s,
23
- source: { key => pointer(error['instanceLocation']) },
24
- title: error['error']
25
- }
26
- end
27
- end
28
-
29
- def validation_errors
30
- validation_output['errors'] || [validation_output]
31
- end
32
-
33
- def default_errors
34
- [{
35
- status: status.to_s,
36
- title: message
37
- }]
38
- end
39
-
40
- def pointer_key
41
- case location
42
- when :body
43
- :pointer
44
- when :query, :path
45
- :parameter
46
- else
47
- location
48
- end
49
- end
50
-
51
- def pointer(data_pointer)
52
- return data_pointer if location == :body
53
-
54
- data_pointer.delete_prefix('/')
55
- end
56
- end
57
- end
58
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- class RequestBodyValidator
5
- def initialize(operation, env)
6
- @operation = operation
7
- @env = env
8
- end
9
-
10
- def validate!
11
- request_body = @operation.request_body
12
- return unless request_body
13
-
14
- request_content_type = Rack::Request.new(@env).content_type
15
- schema = request_body.schema_for(request_content_type)
16
- RequestValidation.fail!(415, :header) unless schema
17
-
18
- parsed_request_body = BodyParser.new.parse_body(@env)
19
- RequestValidation.fail!(400, :body) if request_body.required? && parsed_request_body.nil?
20
-
21
- validate_body!(parsed_request_body, schema)
22
- parsed_request_body
23
- rescue BodyParsingError => e
24
- RequestValidation.fail!(400, :body, message: e.message)
25
- end
26
-
27
- private
28
-
29
- def validate_body!(parsed_request_body, schema)
30
- request_body_schema = schema
31
- return unless request_body_schema
32
-
33
- schema_validation = request_body_schema.validate(parsed_request_body)
34
- RequestValidation.fail!(400, :body, schema_validation:) if schema_validation.error?
35
- end
36
- end
37
- end
@@ -1,122 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rack'
4
- require 'multi_json'
5
- require_relative 'use_router'
6
- require_relative 'error_response'
7
- require_relative 'request_body_validator'
8
- require_relative 'request_validation_error'
9
- require 'openapi_parameters'
10
-
11
- module OpenapiFirst
12
- # A Rack middleware to validate requests against an OpenAPI API description
13
- class RequestValidation
14
- prepend UseRouter
15
-
16
- FAIL = :request_validation_failed
17
- private_constant :FAIL
18
-
19
- # @param status [Integer] The intended HTTP status code (usually 400)
20
- # @param location [Symbol] One of :body, :header, :cookie, :query, :path
21
- # @param schema_validation [OpenapiFirst::Schema::Result]
22
- def self.fail!(status, location, message: nil, schema_validation: nil)
23
- throw FAIL, RequestValidationError.new(
24
- status:,
25
- location:,
26
- message:,
27
- schema_validation:
28
- )
29
- end
30
-
31
- # @param app The parent Rack application
32
- # @param options An optional Hash of configuration options to override defaults
33
- # :error_response A Boolean indicating whether to raise an error if validation fails.
34
- # default: OpenapiFirst::ErrorResponses::Default (Config.default_options.error_response)
35
- # :raise_error The Class to use for error responses.
36
- # default: false (Config.default_options.request_validation_raise_error)
37
- def initialize(app, options = {})
38
- @app = app
39
- @raise = options.fetch(:raise_error, Config.default_options.request_validation_raise_error)
40
- @error_response_class =
41
- Plugins.find_error_response(options.fetch(:error_response, Config.default_options.error_response))
42
- end
43
-
44
- def call(env)
45
- operation = env[OPERATION]
46
- return @app.call(env) unless operation
47
-
48
- error = validate_request(operation, env)
49
- if error
50
- raise RequestInvalidError, error.error_message if @raise
51
-
52
- return @error_response_class.new(env, error).render
53
- end
54
-
55
- @app.call(env)
56
- end
57
-
58
- private
59
-
60
- def validate_request(operation, env)
61
- catch(FAIL) do
62
- env[PARAMS] = {}
63
- validate_parameters!(operation, env)
64
- validate_request_body!(operation, env)
65
- nil
66
- end
67
- end
68
-
69
- def validate_parameters!(operation, env)
70
- validate_query_params!(operation, env)
71
- validate_path_params!(operation, env)
72
- validate_cookie_params!(operation, env)
73
- validate_header_params!(operation, env)
74
- end
75
-
76
- def validate_path_params!(operation, env)
77
- parameters = operation.path_parameters
78
- return unless parameters
79
-
80
- unpacked_params = parameters.unpack(env)
81
- schema_validation = parameters.schema.validate(unpacked_params)
82
- RequestValidation.fail!(400, :path, schema_validation:) if schema_validation.error?
83
- env[PATH_PARAMS] = unpacked_params
84
- env[PARAMS].merge!(unpacked_params)
85
- end
86
-
87
- def validate_query_params!(operation, env)
88
- parameters = operation.query_parameters
89
- return unless parameters
90
-
91
- unpacked_params = parameters.unpack(env)
92
- schema_validation = parameters.schema.validate(unpacked_params)
93
- RequestValidation.fail!(400, :query, schema_validation:) if schema_validation.error?
94
- env[QUERY_PARAMS] = unpacked_params
95
- env[PARAMS].merge!(unpacked_params)
96
- end
97
-
98
- def validate_cookie_params!(operation, env)
99
- parameters = operation.cookie_parameters
100
- return unless parameters
101
-
102
- unpacked_params = parameters.unpack(env)
103
- schema_validation = parameters.schema.validate(unpacked_params)
104
- RequestValidation.fail!(400, :cookie, schema_validation:) if schema_validation.error?
105
- env[COOKIE_PARAMS] = unpacked_params
106
- end
107
-
108
- def validate_header_params!(operation, env)
109
- parameters = operation.header_parameters
110
- return unless parameters
111
-
112
- unpacked_params = parameters.unpack(env)
113
- schema_validation = parameters.schema.validate(unpacked_params)
114
- RequestValidation.fail!(400, :header, schema_validation:) if schema_validation.error?
115
- env[HEADER_PARAMS] = unpacked_params
116
- end
117
-
118
- def validate_request_body!(operation, env)
119
- env[REQUEST_BODY] = RequestBodyValidator.new(operation, env).validate!
120
- end
121
- end
122
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- class RequestValidationError
5
- def initialize(status:, location:, message: nil, schema_validation: nil)
6
- @status = status
7
- @location = location
8
- @message = message
9
- @schema_validation = schema_validation
10
- end
11
-
12
- attr_reader :status, :request, :location, :schema_validation
13
-
14
- def message
15
- @message || schema_validation&.message || Rack::Utils::HTTP_STATUS_CODES[status]
16
- end
17
-
18
- def error_message
19
- "#{TOPICS.fetch(location)} #{message}"
20
- end
21
-
22
- TOPICS = {
23
- body: 'Request body invalid:',
24
- query: 'Query parameter invalid:',
25
- header: 'Header parameter invalid:',
26
- path: 'Path segment invalid:',
27
- cookie: 'Cookie value invalid:'
28
- }.freeze
29
- private_constant :TOPICS
30
- end
31
- end