openapi_first 2.1.1 → 2.2.1

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/README.md +0 -3
  4. data/lib/openapi_first/body_parser.rb +29 -16
  5. data/lib/openapi_first/builder.rb +143 -30
  6. data/lib/openapi_first/definition.rb +5 -5
  7. data/lib/openapi_first/error_responses/default.rb +1 -1
  8. data/lib/openapi_first/error_responses/jsonapi.rb +1 -1
  9. data/lib/openapi_first/file_loader.rb +21 -0
  10. data/lib/openapi_first/json.rb +25 -0
  11. data/lib/openapi_first/json_pointer.rb +22 -0
  12. data/lib/openapi_first/ref_resolver.rb +142 -0
  13. data/lib/openapi_first/request.rb +17 -56
  14. data/lib/openapi_first/request_body_parsers.rb +47 -0
  15. data/lib/openapi_first/request_parser.rb +11 -9
  16. data/lib/openapi_first/request_validator.rb +16 -9
  17. data/lib/openapi_first/response.rb +3 -21
  18. data/lib/openapi_first/response_body_parsers.rb +29 -0
  19. data/lib/openapi_first/response_parser.rb +9 -26
  20. data/lib/openapi_first/response_validator.rb +2 -2
  21. data/lib/openapi_first/test/methods.rb +9 -10
  22. data/lib/openapi_first/test/minitest_helpers.rb +28 -0
  23. data/lib/openapi_first/test/plain_helpers.rb +26 -0
  24. data/lib/openapi_first/test.rb +6 -0
  25. data/lib/openapi_first/validated_request.rb +13 -29
  26. data/lib/openapi_first/validators/request_body.rb +9 -23
  27. data/lib/openapi_first/validators/request_parameters.rb +17 -25
  28. data/lib/openapi_first/validators/response_body.rb +7 -3
  29. data/lib/openapi_first/validators/response_headers.rb +6 -4
  30. data/lib/openapi_first/version.rb +1 -1
  31. data/lib/openapi_first.rb +10 -17
  32. metadata +11 -23
  33. data/lib/openapi_first/json_refs.rb +0 -151
  34. data/lib/openapi_first/schema.rb +0 -44
@@ -11,82 +11,43 @@ module OpenapiFirst
11
11
  # This class represents one of those requests.
12
12
  class Request
13
13
  def initialize(path:, request_method:, operation_object:,
14
- parameters:, content_type:, content_schema:, required_body:,
15
- hooks:, openapi_version:)
14
+ parameters:, content_type:, content_schema:, required_body:)
16
15
  @path = path
17
16
  @request_method = request_method
18
17
  @content_type = content_type
19
18
  @content_schema = content_schema
20
- @required_request_body = required_body == true
21
19
  @operation = operation_object
22
- @parameters = build_parameters(parameters)
23
20
  @request_parser = RequestParser.new(
24
- query_parameters: @parameters[:query],
25
- path_parameters: @parameters[:path],
26
- header_parameters: @parameters[:header],
27
- cookie_parameters: @parameters[:cookie],
21
+ query_parameters: parameters.query,
22
+ path_parameters: parameters.path,
23
+ header_parameters: parameters.header,
24
+ cookie_parameters: parameters.cookie,
28
25
  content_type:
29
26
  )
30
- @validator = RequestValidator.new(self, hooks:, openapi_version:)
27
+ @validator = RequestValidator.new(
28
+ content_schema:,
29
+ required_request_body: required_body == true,
30
+ path_schema: parameters.path_schema,
31
+ query_schema: parameters.query_schema,
32
+ header_schema: parameters.header_schema,
33
+ cookie_schema: parameters.cookie_schema
34
+ )
31
35
  end
32
36
 
33
37
  attr_reader :content_type, :content_schema, :operation, :request_method, :path
34
38
 
35
39
  def validate(request, route_params:)
36
- parsed_values = {}
40
+ parsed_request = nil
37
41
  error = catch FAILURE do
38
- parsed_values = @request_parser.parse(request, route_params:)
39
- @validator.call(parsed_values)
42
+ parsed_request = @request_parser.parse(request, route_params:)
43
+ @validator.call(parsed_request)
40
44
  nil
41
45
  end
42
- ValidatedRequest.new(request, parsed_values:, error:, request_definition: self)
43
- end
44
-
45
- # These return a Schema instance for each type of parameters
46
- %i[path query header cookie].each do |location|
47
- define_method(:"#{location}_schema") do
48
- build_parameters_schema(@parameters[location])
49
- end
50
- end
51
-
52
- def required_request_body?
53
- @required_request_body
46
+ ValidatedRequest.new(request, parsed_request:, error:, request_definition: self)
54
47
  end
55
48
 
56
49
  def operation_id
57
50
  @operation['operationId']
58
51
  end
59
-
60
- private
61
-
62
- IGNORED_HEADERS = Set['Content-Type', 'Accept', 'Authorization'].freeze
63
- private_constant :IGNORED_HEADERS
64
-
65
- def build_parameters(parameter_definitions)
66
- result = {}
67
- parameter_definitions&.each do |parameter|
68
- (result[parameter['in'].to_sym] ||= []) << parameter
69
- end
70
- result[:header]&.reject! { IGNORED_HEADERS.include?(_1['name']) }
71
- result
72
- end
73
-
74
- def build_parameters_schema(parameters)
75
- return unless parameters
76
-
77
- properties = {}
78
- required = []
79
- parameters.each do |parameter|
80
- schema = parameter['schema']
81
- name = parameter['name']
82
- properties[name] = schema if schema
83
- required << name if parameter['required']
84
- end
85
-
86
- {
87
- 'properties' => properties,
88
- 'required' => required
89
- }
90
- end
91
52
  end
92
53
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ # @!visibility private
5
+ module RequestBodyParsers
6
+ DEFAULT = ->(request) { Utils.read_body(request) }
7
+
8
+ @parsers = {}
9
+
10
+ class << self
11
+ attr_reader :parsers
12
+
13
+ def register(pattern, parser)
14
+ parsers[pattern] = parser
15
+ end
16
+
17
+ def [](content_type)
18
+ key = parsers.keys.find { content_type.match?(_1) }
19
+ parsers.fetch(key) { DEFAULT }
20
+ end
21
+ end
22
+
23
+ # Not sure where to put this
24
+ module Utils
25
+ def self.read_body(request)
26
+ body = request.body&.read
27
+ request.body.rewind if request.body.respond_to?(:rewind)
28
+ body
29
+ end
30
+ end
31
+
32
+ register(/json/i, lambda do |request|
33
+ body = Utils.read_body(request)
34
+ JSON.parse(body) unless body.nil? || body.empty?
35
+ rescue JSON::ParserError
36
+ Failure.fail!(:invalid_body, message: 'Failed to parse request body as JSON')
37
+ end)
38
+
39
+ register('multipart/form-data', lambda { |request|
40
+ request.POST.transform_values do |value|
41
+ value.is_a?(Hash) && value[:tempfile] ? value[:tempfile].read : value
42
+ end
43
+ })
44
+
45
+ register('application/x-www-form-urlencoded', lambda(&:POST))
46
+ end
47
+ end
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'openapi_parameters'
4
- require_relative 'body_parser'
4
+ require_relative 'request_body_parsers'
5
5
 
6
6
  module OpenapiFirst
7
+ ParsedRequest = Data.define(:path, :query, :headers, :body, :cookies)
8
+
7
9
  # Parse a request
8
10
  class RequestParser
9
11
  def initialize(
@@ -17,19 +19,19 @@ module OpenapiFirst
17
19
  @path_parser = OpenapiParameters::Path.new(path_parameters) if path_parameters
18
20
  @headers_parser = OpenapiParameters::Header.new(header_parameters) if header_parameters
19
21
  @cookies_parser = OpenapiParameters::Cookie.new(cookie_parameters) if cookie_parameters
20
- @body_parser = BodyParser.new(content_type) if content_type
22
+ @body_parsers = RequestBodyParsers[content_type] if content_type
21
23
  end
22
24
 
23
25
  attr_reader :query, :path, :headers, :cookies
24
26
 
25
27
  def parse(request, route_params:)
26
- result = {}
27
- result[:path] = @path_parser.unpack(route_params) if @path_parser
28
- result[:query] = @query_parser.unpack(request.env[Rack::QUERY_STRING]) if @query_parser
29
- result[:headers] = @headers_parser.unpack_env(request.env) if @headers_parser
30
- result[:cookies] = @cookies_parser.unpack(request.env[Rack::HTTP_COOKIE]) if @cookies_parser
31
- result[:body] = @body_parser.parse(request) if @body_parser
32
- result
28
+ ParsedRequest.new(
29
+ path: @path_parser&.unpack(route_params),
30
+ query: @query_parser&.unpack(request.env[Rack::QUERY_STRING]),
31
+ headers: @headers_parser&.unpack_env(request.env),
32
+ cookies: @cookies_parser&.unpack(request.env[Rack::HTTP_COOKIE]),
33
+ body: @body_parsers&.call(request)
34
+ )
33
35
  end
34
36
  end
35
37
  end
@@ -7,15 +7,22 @@ require_relative 'validators/request_body'
7
7
  module OpenapiFirst
8
8
  # Validates a Request against a request definition.
9
9
  class RequestValidator
10
- VALIDATORS = [
11
- Validators::RequestParameters,
12
- Validators::RequestBody
13
- ].freeze
14
-
15
- def initialize(request_definition, openapi_version:, hooks: {})
16
- @validators = VALIDATORS.filter_map do |klass|
17
- klass.for(request_definition, hooks:, openapi_version:)
18
- end
10
+ def initialize(
11
+ content_schema:,
12
+ required_request_body:,
13
+ path_schema:,
14
+ query_schema:,
15
+ header_schema:,
16
+ cookie_schema:
17
+ )
18
+ @validators = []
19
+ @validators << Validators::RequestBody.new(content_schema:, required_request_body:) if content_schema
20
+ @validators.concat Validators::RequestParameters.for(
21
+ path_schema:,
22
+ query_schema:,
23
+ header_schema:,
24
+ cookie_schema:
25
+ )
19
26
  end
20
27
 
21
28
  def call(parsed_request)
@@ -9,14 +9,14 @@ module OpenapiFirst
9
9
  # This is not a direct reflecton of the OpenAPI 3.X response definition, but a combination of
10
10
  # status, content type and content schema.
11
11
  class Response
12
- def initialize(status:, headers:, content_type:, content_schema:, openapi_version:)
12
+ def initialize(status:, headers:, headers_schema:, content_type:, content_schema:)
13
13
  @status = status
14
14
  @content_type = content_type
15
15
  @content_schema = content_schema
16
16
  @headers = headers
17
- @headers_schema = build_headers_schema(headers)
17
+ @headers_schema = headers_schema
18
18
  @parser = ResponseParser.new(headers:, content_type:)
19
- @validator = ResponseValidator.new(self, openapi_version:)
19
+ @validator = ResponseValidator.new(self)
20
20
  end
21
21
 
22
22
  # @attr_reader [Integer] status The HTTP status code of the response definition.
@@ -35,23 +35,5 @@ module OpenapiFirst
35
35
  def parse(request)
36
36
  @parser.parse(request)
37
37
  end
38
-
39
- def build_headers_schema(headers_object)
40
- return unless headers_object&.any?
41
-
42
- properties = {}
43
- required = []
44
- headers_object.each do |name, header|
45
- schema = header['schema']
46
- next if name.casecmp('content-type').zero?
47
-
48
- properties[name] = schema if schema
49
- required << name if header['required']
50
- end
51
- {
52
- 'properties' => properties,
53
- 'required' => required
54
- }
55
- end
56
38
  end
57
39
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ # @visibility private
5
+ module ResponseBodyParsers
6
+ DEFAULT = ->(body) { body }
7
+
8
+ @parsers = {}
9
+
10
+ class << self
11
+ attr_reader :parsers
12
+
13
+ def register(pattern, parser)
14
+ parsers[pattern] = parser
15
+ end
16
+
17
+ def [](content_type)
18
+ key = parsers.keys.find { content_type&.match?(_1) }
19
+ parsers.fetch(key) { DEFAULT }
20
+ end
21
+ end
22
+
23
+ register(/json/i, lambda do |body|
24
+ JSON.parse(body)
25
+ rescue JSON::ParserError
26
+ Failure.fail!(:invalid_response_body, message: 'Response body is invalid: Failed to parse response body as JSON')
27
+ end)
28
+ end
29
+ end
@@ -1,40 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'response_body_parsers'
4
+
3
5
  module OpenapiFirst
4
6
  ParsedResponse = Data.define(:body, :headers)
5
7
 
6
8
  # Parse a response
7
9
  class ResponseParser
8
10
  def initialize(headers:, content_type:)
9
- @headers = headers
10
- @json = /json/i.match?(content_type)
11
+ @headers_parser = build_headers_parser(headers)
12
+ @body_parser = ResponseBodyParsers[content_type]
11
13
  end
12
14
 
13
15
  def parse(rack_response)
14
16
  ParsedResponse.new(
15
- body: parse_body(read_body(rack_response)),
16
- headers: parse_headers(rack_response)
17
+ body: @body_parser.call(read_body(rack_response)),
18
+ headers: @headers_parser.call(rack_response.headers)
17
19
  )
18
20
  end
19
21
 
20
22
  private
21
23
 
22
- attr_reader :headers
23
-
24
- def json? = @json
25
-
26
- def parse_body(body)
27
- return parse_json(body) if json?
28
-
29
- body
30
- end
31
-
32
- def parse_json(body)
33
- MultiJson.load(body)
34
- rescue MultiJson::ParseError
35
- Failure.fail!(:invalid_response_body, message: 'Response body is invalid: Failed to parse response body as JSON')
36
- end
37
-
38
24
  def read_body(rack_response)
39
25
  buffered_body = +''
40
26
  if rack_response.body.respond_to?(:each)
@@ -44,14 +30,11 @@ module OpenapiFirst
44
30
  rack_response.body
45
31
  end
46
32
 
47
- def parse_headers(rack_response)
48
- return {} if headers.nil?
49
-
50
- # TODO: memoize unpacker
51
- headers_as_parameters = headers.map do |name, definition|
33
+ def build_headers_parser(header_definitions)
34
+ headers_as_parameters = header_definitions.to_a.map do |name, definition|
52
35
  definition.merge('name' => name, 'in' => 'header')
53
36
  end
54
- OpenapiParameters::Header.new(headers_as_parameters).unpack(rack_response.headers)
37
+ OpenapiParameters::Header.new(headers_as_parameters).method(:unpack)
55
38
  end
56
39
  end
57
40
  end
@@ -11,9 +11,9 @@ module OpenapiFirst
11
11
  Validators::ResponseBody
12
12
  ].freeze
13
13
 
14
- def initialize(response_definition, openapi_version:)
14
+ def initialize(response_definition)
15
15
  @validators = VALIDATORS.filter_map do |klass|
16
- klass.for(response_definition, openapi_version:)
16
+ klass.for(response_definition)
17
17
  end
18
18
  end
19
19
 
@@ -1,20 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'minitest_helpers'
4
+ require_relative 'plain_helpers'
5
+
3
6
  module OpenapiFirst
7
+ # Test integration
4
8
  module Test
5
9
  # Methods to use in integration tests
6
10
  module Methods
7
- def assert_api_conform(status: nil, api: :default)
8
- api = OpenapiFirst::Test[api]
9
- request = respond_to?(:last_request) ? last_request : @request
10
- response = respond_to?(:last_response) ? last_response : @response
11
- if status && status != response.status
12
- raise OpenapiFirst::Error,
13
- "Expected status #{status}, but got #{response.status} " \
14
- "from #{request.request_method.upcase} #{request.path}."
11
+ def self.included(base)
12
+ if Test.minitest?(base)
13
+ base.include(OpenapiFirst::Test::MinitestHelpers)
14
+ else
15
+ base.include(OpenapiFirst::Test::PlainHelpers)
15
16
  end
16
- api.validate_request(request, raise_error: true)
17
- api.validate_response(request, response, raise_error: true)
18
17
  end
19
18
  end
20
19
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ module Test
5
+ # Assertion methods for Minitest
6
+ module MinitestHelpers
7
+ # :nocov:
8
+ def assert_api_conform(status: nil, api: :default)
9
+ api = OpenapiFirst::Test[api]
10
+ request = respond_to?(:last_request) ? last_request : @request
11
+ response = respond_to?(:last_response) ? last_response : @response
12
+
13
+ if status
14
+ assert_equal status, response.status,
15
+ "Expected status #{status}, but got #{response.status} " \
16
+ "from #{request.request_method.upcase} #{request.path}."
17
+ end
18
+
19
+ validated_request = api.validate_request(request, raise_error: false)
20
+ validated_response = api.validate_response(request, response, raise_error: false)
21
+
22
+ assert validated_request.valid?, validated_request.error&.exception_message
23
+ assert validated_response.valid?, validated_response.error&.exception_message
24
+ end
25
+ # :nocov:
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ module Test
5
+ # Assertion methods to use when no known test framework was found
6
+ # These methods just raise an exception if an error was found
7
+ module PlainHelpers
8
+ def assert_api_conform(status: nil, api: :default)
9
+ api = OpenapiFirst::Test[api]
10
+ # :nocov:
11
+ request = respond_to?(:last_request) ? last_request : @request
12
+ response = respond_to?(:last_response) ? last_response : @response
13
+ # :nocov:
14
+
15
+ if status && status != response.status
16
+ raise OpenapiFirst::Error,
17
+ "Expected status #{status}, but got #{response.status} " \
18
+ "from #{request.request_method.upcase} #{request.path}."
19
+ end
20
+
21
+ api.validate_request(request, raise_error: true)
22
+ api.validate_response(request, response, raise_error: true)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -5,6 +5,12 @@ require_relative 'test/methods'
5
5
  module OpenapiFirst
6
6
  # Test integration
7
7
  module Test
8
+ def self.minitest?(base)
9
+ base.include?(::Minitest::Assertions)
10
+ rescue NameError
11
+ false
12
+ end
13
+
8
14
  class NotRegisteredError < StandardError; end
9
15
 
10
16
  DEFINITIONS = {} # rubocop:disable Style/MutableConstant
@@ -8,9 +8,9 @@ module OpenapiFirst
8
8
  class ValidatedRequest < SimpleDelegator
9
9
  extend Forwardable
10
10
 
11
- def initialize(original_request, error:, parsed_values: {}, request_definition: nil)
11
+ def initialize(original_request, error:, parsed_request: nil, request_definition: nil)
12
12
  super(original_request)
13
- @parsed_values = Hash.new({}).merge(parsed_values)
13
+ @parsed_request = parsed_request
14
14
  @error = error
15
15
  @request_definition = request_definition
16
16
  end
@@ -33,57 +33,41 @@ module OpenapiFirst
33
33
 
34
34
  # Parsed path parameters
35
35
  # @return [Hash<String, anything>]
36
- def parsed_path_parameters
37
- @parsed_values[:path]
38
- end
36
+ def parsed_path_parameters = @parsed_request&.path || {}
39
37
 
40
38
  # Parsed query parameters. This only returns the query parameters that are defined in the OpenAPI spec.
41
39
  # @return [Hash<String, anything>]
42
- def parsed_query
43
- @parsed_values[:query]
44
- end
40
+ def parsed_query = @parsed_request&.query || {}
45
41
 
46
42
  # Parsed headers. This only returns the query parameters that are defined in the OpenAPI spec.
47
43
  # @return [Hash<String, anything>]
48
- def parsed_headers
49
- @parsed_values[:headers]
50
- end
44
+ def parsed_headers = @parsed_request&.headers || {}
51
45
 
52
46
  # Parsed cookies. This only returns the query parameters that are defined in the OpenAPI spec.
53
47
  # @return [Hash<String, anything>]
54
- def parsed_cookies
55
- @parsed_values[:cookies]
56
- end
48
+ def parsed_cookies = @parsed_request&.cookies || {}
57
49
 
58
50
  # Parsed body. This parses the body according to the content type.
59
51
  # Note that this returns the hole body, not only the fields that are defined in the OpenAPI spec.
60
52
  # You can use JSON Schemas `additionalProperties` or `unevaluatedProperties` to
61
- # returns a validation error if the body contains unknown fields.
62
- # @return [Hash<String, anything>]
63
- def parsed_body
64
- @parsed_values[:body]
65
- end
53
+ # return a validation error if the body contains unknown fields.
54
+ # @return [Hash<String, anything>, anything]
55
+ def parsed_body = @parsed_request&.body
66
56
 
67
57
  # Checks if the request is valid.
68
- def valid?
69
- error.nil?
70
- end
58
+ def valid? = error.nil?
71
59
 
72
60
  # Checks if the request is invalid.
73
- def invalid?
74
- !valid?
75
- end
61
+ def invalid? = !valid?
76
62
 
77
63
  # Returns true if the request is defined.
78
- def known?
79
- request_definition != nil
80
- end
64
+ def known? = request_definition != nil
81
65
 
82
66
  # Merged path, query, body parameters.
83
67
  # Here path has the highest precedence, then query, then body.
84
68
  # @return [Hash<String, anything>]
85
69
  def parsed_params
86
- @parsed_params ||= parsed_body.merge(parsed_query, parsed_path_parameters)
70
+ @parsed_params ||= parsed_body.to_h.merge(parsed_query, parsed_path_parameters) || {}
87
71
  end
88
72
  end
89
73
  end
@@ -3,37 +3,23 @@
3
3
  module OpenapiFirst
4
4
  module Validators
5
5
  class RequestBody
6
- def self.for(request_definition, openapi_version:, hooks: {})
7
- schema = request_definition.content_schema
8
- return unless schema
9
-
10
- after_property_validation = hooks[:after_request_body_property_validation]
11
-
12
- new(Schema.new(schema, after_property_validation:, openapi_version:),
13
- required: request_definition.required_request_body?)
14
- end
15
-
16
- def initialize(schema, required:)
17
- @schema = schema
18
- @required = required
6
+ def initialize(content_schema:, required_request_body:)
7
+ @schema = content_schema
8
+ @required = required_request_body
19
9
  end
20
10
 
21
- def call(request)
22
- request_body = read_body(request)
23
- if request_body.nil?
11
+ def call(parsed_request)
12
+ body = parsed_request.body
13
+ if body.nil?
24
14
  Failure.fail!(:invalid_body, message: 'Request body is not defined') if @required
25
15
  return
26
16
  end
27
17
 
28
- validation = @schema.validate(request_body)
18
+ validation = Schema::ValidationResult.new(
19
+ @schema.validate(body, access_mode: 'write')
20
+ )
29
21
  Failure.fail!(:invalid_body, errors: validation.errors) if validation.error?
30
22
  end
31
-
32
- private
33
-
34
- def read_body(request)
35
- request[:body]
36
- end
37
23
  end
38
24
  end
39
25
  end
@@ -2,31 +2,35 @@
2
2
 
3
3
  module OpenapiFirst
4
4
  module Validators
5
- class RequestParameters
5
+ module RequestParameters
6
6
  RequestHeaders = Data.define(:schema) do
7
- def call(parsed_values)
8
- validation = schema.validate(parsed_values[:headers])
7
+ def call(parsed_request)
8
+ validation = schema.validate(parsed_request.headers)
9
+ validation = Schema::ValidationResult.new(validation.to_a)
9
10
  Failure.fail!(:invalid_header, errors: validation.errors) if validation.error?
10
11
  end
11
12
  end
12
13
 
13
14
  Path = Data.define(:schema) do
14
- def call(parsed_values)
15
- validation = schema.validate(parsed_values[:path])
15
+ def call(parsed_request)
16
+ validation = schema.validate(parsed_request.path)
17
+ validation = Schema::ValidationResult.new(validation.to_a)
16
18
  Failure.fail!(:invalid_path, errors: validation.errors) if validation.error?
17
19
  end
18
20
  end
19
21
 
20
22
  Query = Data.define(:schema) do
21
- def call(parsed_values)
22
- validation = schema.validate(parsed_values[:query])
23
+ def call(parsed_request)
24
+ validation = schema.validate(parsed_request.query)
25
+ validation = Schema::ValidationResult.new(validation.to_a)
23
26
  Failure.fail!(:invalid_query, errors: validation.errors) if validation.error?
24
27
  end
25
28
  end
26
29
 
27
30
  RequestCookies = Data.define(:schema) do
28
- def call(parsed_values)
29
- validation = schema.validate(parsed_values[:cookies])
31
+ def call(parsed_request)
32
+ validation = schema.validate(parsed_request.cookies)
33
+ validation = Schema::ValidationResult.new(validation.to_a)
30
34
  Failure.fail!(:invalid_cookie, errors: validation.errors) if validation.error?
31
35
  end
32
36
  end
@@ -38,23 +42,11 @@ module OpenapiFirst
38
42
  cookie_schema: RequestCookies
39
43
  }.freeze
40
44
 
41
- def self.for(operation, openapi_version:, hooks: {})
42
- after_property_validation = hooks[:after_request_parameter_property_validation]
43
- validators = VALIDATORS.filter_map do |key, klass|
44
- schema = operation.send(key)
45
- klass.new(Schema.new(schema, after_property_validation:, openapi_version:)) if schema
45
+ def self.for(args)
46
+ VALIDATORS.filter_map do |key, klass|
47
+ schema = args[key]
48
+ klass.new(schema) if schema.value
46
49
  end
47
- return if validators.empty?
48
-
49
- new(validators)
50
- end
51
-
52
- def initialize(validators)
53
- @validators = validators
54
- end
55
-
56
- def call(parsed_values)
57
- @validators.each { |validator| validator.call(parsed_values) }
58
50
  end
59
51
  end
60
52
  end