openapi_first 1.0.0.beta6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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