openapi_first 1.1.1 → 1.3.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openapi_first/body_parser.rb +3 -1
  3. data/lib/openapi_first/configuration.rb +3 -1
  4. data/lib/openapi_first/definition/operation.rb +65 -5
  5. data/lib/openapi_first/definition/path_item.rb +1 -0
  6. data/lib/openapi_first/definition/request_body.rb +1 -0
  7. data/lib/openapi_first/definition/response.rb +7 -0
  8. data/lib/openapi_first/definition.rb +43 -3
  9. data/lib/openapi_first/error_response.rb +1 -1
  10. data/lib/openapi_first/errors.rb +6 -0
  11. data/lib/openapi_first/failure.rb +28 -4
  12. data/lib/openapi_first/middlewares/request_validation.rb +2 -5
  13. data/lib/openapi_first/middlewares/response_validation.rb +1 -4
  14. data/lib/openapi_first/plugins/default/error_response.rb +4 -4
  15. data/lib/openapi_first/plugins/default.rb +1 -1
  16. data/lib/openapi_first/plugins/jsonapi/error_response.rb +3 -2
  17. data/lib/openapi_first/plugins/jsonapi.rb +1 -1
  18. data/lib/openapi_first/plugins.rb +1 -0
  19. data/lib/openapi_first/request_validation/request_body_validator.rb +1 -1
  20. data/lib/openapi_first/request_validation/validator.rb +1 -0
  21. data/lib/openapi_first/response_validation/validator.rb +1 -0
  22. data/lib/openapi_first/runtime_request.rb +63 -3
  23. data/lib/openapi_first/runtime_response.rb +43 -4
  24. data/lib/openapi_first/schema/validation_error.rb +2 -0
  25. data/lib/openapi_first/schema/validation_result.rb +2 -7
  26. data/lib/openapi_first/schema.rb +1 -0
  27. data/lib/openapi_first/version.rb +1 -1
  28. data/lib/openapi_first.rb +21 -3
  29. metadata +6 -17
  30. data/.github/CODEOWNERS +0 -1
  31. data/.github/workflows/ruby.yml +0 -13
  32. data/.gitignore +0 -11
  33. data/CHANGELOG.md +0 -274
  34. data/Gemfile +0 -18
  35. data/Gemfile.lock +0 -170
  36. data/Gemfile.rack2 +0 -15
  37. data/Gemfile.rack2.lock +0 -99
  38. data/LICENSE.txt +0 -21
  39. data/README.md +0 -225
  40. data/openapi_first.gemspec +0 -47
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bb6d0ee4dbe98020ef124e79a99ced0d0111b1e2891cc8cb3ed8bb697973d2b
4
- data.tar.gz: 77ce896a68f885614f64fd680af0dde1860c07ae772ce7d5f7d1b75b5abb4528
3
+ metadata.gz: caea1ca3e63935e0d04a52bade49e9f8270da3bdcf3b3cb89e3791cc202c1a79
4
+ data.tar.gz: 3d1da5e269e0328ec383b30cf29486b1d49aa91317e428626c26f9284eb1d55c
5
5
  SHA512:
6
- metadata.gz: 841e32068646969d92ab26fff9c332e849056463c99805c8e0dbbb437918113a09750fb5ceffd3940716911ea50bc20685acbcd862aa6acc270e43fe43675c87
7
- data.tar.gz: d9a225b3e3119512fc3ed585f00f6f915e21f3199206f520d20733999441567e651fcb129588092c4e7ea9dcc4ce1e77c24365b04b8a8d9d232b8a1a5cd8e1da
6
+ metadata.gz: 0a48588e004db687e0dee2b54982837aebe3dcb3d65cf3191141b59d7f63d945083dd0bc364346acaa4442420101310ffc174383ee6e2897468b6680f90c4172
7
+ data.tar.gz: 352789bc86107fc3253cb08a3771399e5ecee50189c119903bc678f1de7eb078a6bc89a797bc22322ae52beb3de30c64de612fb6350d572cc6a6a1c1cb6fd067
@@ -3,10 +3,12 @@
3
3
  require 'multi_json'
4
4
 
5
5
  module OpenapiFirst
6
+ # @!visibility private
6
7
  class BodyParser
7
8
  def self.const_missing(const_name)
8
9
  super unless const_name == :ParsingError
9
- warn 'DEPRECATION WARNING: OpenapiFirst::BodyParser::ParsingError is deprecated. Use OpenapiFirst::ParseError instead.' # rubocop:disable Layout/LineLength
10
+ warn 'DEPRECATION WARNING: OpenapiFirst::BodyParser::ParsingError is deprecated. ' \
11
+ 'Use OpenapiFirst::ParseError instead.'
10
12
  OpenapiFirst::ParseError
11
13
  end
12
14
 
@@ -1,13 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiFirst
4
+ # Global configuration. Currently only used for the request validation middleware.
4
5
  class Configuration
5
6
  def initialize
6
7
  @request_validation_error_response = OpenapiFirst.plugin(:default)::ErrorResponse
7
8
  @request_validation_raise_error = false
8
9
  end
9
10
 
10
- attr_reader :request_validation_error_response, :request_validation_raise_error
11
+ attr_reader :request_validation_error_response
12
+ attr_accessor :request_validation_raise_error
11
13
 
12
14
  def request_validation_error_response=(mod)
13
15
  @request_validation_error_response = if mod.is_a?(Symbol)
@@ -8,11 +8,14 @@ require_relative 'responses'
8
8
 
9
9
  module OpenapiFirst
10
10
  class Definition
11
+ # Represents an operation object in the OpenAPI 3.X specification.
12
+ # Use this class to access information about the operation. Use `#[key]` to read the raw data.
13
+ # When using the middleware you can access the operation object via `env[OpenapiFirst::REQUEST].operation`.
11
14
  class Operation
12
15
  extend Forwardable
16
+
13
17
  def_delegators :operation_object,
14
- :[],
15
- :dig
18
+ :[]
16
19
 
17
20
  WRITE_METHODS = Set.new(%w[post put patch delete]).freeze
18
21
  private_constant :WRITE_METHODS
@@ -25,31 +28,62 @@ module OpenapiFirst
25
28
  @operation_object = @path_item_object[request_method]
26
29
  end
27
30
 
28
- attr_reader :path, :method, :openapi_version
31
+ # Returns the path of the operation as in the API description.
32
+ # @return [String] The path of the operation.
33
+ attr_reader :path
34
+
35
+ # Returns the (downcased) request method of the operation.
36
+ # Example: "get"
37
+ # @return [String] The request method of the operation.
38
+ attr_reader :method
29
39
  alias request_method method
30
40
 
41
+ attr_reader :openapi_version # :nodoc:
42
+
43
+ # Returns the operation ID as defined in the API description.
44
+ # @return [String, nil]
31
45
  def operation_id
32
46
  operation_object['operationId']
33
47
  end
34
48
 
49
+ # Checks if the operation is a read operation.
50
+ # This is the case for all request methods except POST, PUT, PATCH and DELETE.
51
+ # @return [Boolean] `true` if the operation is a read operation, `false` otherwise.
35
52
  def read?
36
53
  !write?
37
54
  end
38
55
 
56
+ # Checks if the operation is a write operation.
57
+ # This is the case for POST, PUT, PATCH and DELETE request methods.
58
+ # @return [Boolean] `true` if the operation is a write operation, `false` otherwise.
39
59
  def write?
40
60
  WRITE_METHODS.include?(method)
41
61
  end
42
62
 
63
+ # Returns the request body definition if defined in the API description.
64
+ # @return [RequestBody, nil] The request body of the operation, or `nil` if not present.
43
65
  def request_body
44
66
  @request_body ||= RequestBody.new(operation_object['requestBody'], self) if operation_object['requestBody']
45
67
  end
46
68
 
69
+ # Checks if a response status is defined for this operation.
70
+ # @param status [Integer, String] The response status to check.
71
+ # @return [Boolean] `true` if the response status is defined, `false` otherwise.
47
72
  def response_status_defined?(status)
48
73
  responses.status_defined?(status)
49
74
  end
50
75
 
51
- def_delegators :responses, :response_for
76
+ # Returns the response object for a given status.
77
+ # @param status [Integer, String] The response status.
78
+ # @param content_type [String] Content-Type of the current response.
79
+ # @return [Response, nil] The response object for the given status, or `nil` if not found.
80
+ def response_for(status, content_type)
81
+ responses.response_for(status, content_type)
82
+ end
52
83
 
84
+ # Returns the schema for a given content type.
85
+ # @param content_type [String] The content type.
86
+ # @return [Schema, nil] The schema for the given content type, or `nil` if not found.
53
87
  def schema_for(content_type)
54
88
  content = @request_body_object['content']
55
89
  return unless content&.any?
@@ -60,46 +94,72 @@ module OpenapiFirst
60
94
  end
61
95
  end
62
96
 
97
+ # Returns a unique name for this operation. Used for generating error messages.
98
+ # @visibility private
63
99
  def name
64
100
  @name ||= "#{method.upcase} #{path} (#{operation_id})"
65
101
  end
66
102
 
103
+ # Returns the path parameters of the operation.
104
+ # @return [Array<Hash>] The path parameters of the operation.
67
105
  def path_parameters
68
106
  all_parameters['path']
69
107
  end
70
108
 
109
+ # Returns the query parameters of the operation.
110
+ # Returns parameters defined on the path and in the operation.
111
+ # @return [Array<Hash>] The query parameters of the operation.
71
112
  def query_parameters
72
113
  all_parameters['query']
73
114
  end
74
115
 
116
+ # Returns the header parameters of the operation.
117
+ # Returns parameters defined on the path and in the operation.
118
+ # @return [Array<Hash>] The header parameters of the operation.
75
119
  def header_parameters
76
120
  all_parameters['header']
77
121
  end
78
122
 
123
+ # Returns the cookie parameters of the operation.
124
+ # Returns parameters defined on the path and in the operation.
125
+ # @return [Array<Hash>] The cookie parameters of the operation.
79
126
  def cookie_parameters
80
127
  all_parameters['cookie']
81
128
  end
82
129
 
130
+ # Returns the schema for the path parameters.
131
+ # @visibility private
132
+ # @return [Schema, nil] The schema for the path parameters, or `nil` if not found.
83
133
  def path_parameters_schema
84
134
  @path_parameters_schema ||= build_schema(path_parameters)
85
135
  end
86
136
 
137
+ # Returns the schema for the query parameters.
138
+ # @visibility private
139
+ # @return [Schema, nil] The schema for the query parameters, or `nil` if not found.
87
140
  def query_parameters_schema
88
141
  @query_parameters_schema ||= build_schema(query_parameters)
89
142
  end
90
143
 
144
+ # Returns the schema for the header parameters.
145
+ # @visibility private
146
+ # @return [Schema, nil] The schema for the header parameters, or `nil` if not found.
91
147
  def header_parameters_schema
92
148
  @header_parameters_schema ||= build_schema(header_parameters)
93
149
  end
94
150
 
151
+ # Returns the schema for the cookie parameters.
152
+ # @visibility private
153
+ # @return [Schema, nil] The schema for the cookie parameters, or `nil` if not found.
95
154
  def cookie_parameters_schema
96
155
  @cookie_parameters_schema ||= build_schema(cookie_parameters)
97
156
  end
98
157
 
99
158
  private
100
159
 
160
+ WRITE_METHODS = Set.new(%w[post put patch delete]).freeze
161
+
101
162
  IGNORED_HEADERS = Set['Content-Type', 'Accept', 'Authorization'].freeze
102
- private_constant :IGNORED_HEADERS
103
163
 
104
164
  def all_parameters
105
165
  @all_parameters ||= (@path_item_object.fetch('parameters', []) + operation_object.fetch('parameters', []))
@@ -4,6 +4,7 @@ require_relative 'operation'
4
4
 
5
5
  module OpenapiFirst
6
6
  class Definition
7
+ # A pathItem as defined in the OpenAPI document.
7
8
  class PathItem
8
9
  def initialize(path, path_item_object, openapi_version:)
9
10
  @path = path
@@ -4,6 +4,7 @@ require_relative '../schema'
4
4
 
5
5
  module OpenapiFirst
6
6
  class Definition
7
+ # Represents a request body definition in the OpenAPI document that belongs to an operation.
7
8
  class RequestBody
8
9
  def initialize(request_body_object, operation)
9
10
  @request_body_object = request_body_object
@@ -2,6 +2,9 @@
2
2
 
3
3
  module OpenapiFirst
4
4
  class Definition
5
+ # Represents a response definition in the OpenAPI document.
6
+ # This is not a direct reflecton of the OpenAPI 3.X response definition, but a combination of
7
+ # status, content type and content schema.
5
8
  class Response
6
9
  def initialize(operation:, status:, response_object:, content_type:, content_schema:)
7
10
  @operation = operation
@@ -11,6 +14,10 @@ module OpenapiFirst
11
14
  @content_schema = content_schema
12
15
  end
13
16
 
17
+ # @attr_reader [Operation] operation The operation this response belongs to.
18
+ # @attr_reader [Integer] status The HTTP status code of the response definition.
19
+ # @attr_reader [String, nil] content_type Content type of this response.
20
+ # @attr_reader [Schema, nil] content_schema the Schema of the response body.
14
21
  attr_reader :operation, :status, :content_type, :content_schema
15
22
 
16
23
  def headers
@@ -1,20 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'mustermann/template'
3
+ require 'mustermann'
4
4
  require_relative 'definition/path_item'
5
5
  require_relative 'runtime_request'
6
+ require_relative 'request_validation/validator'
7
+ require_relative 'response_validation/validator'
6
8
 
7
9
  module OpenapiFirst
8
10
  # Represents an OpenAPI API Description document
11
+ # This is returned by OpenapiFirst.load.
9
12
  class Definition
10
13
  attr_reader :filepath, :paths, :openapi_version
11
14
 
12
- def initialize(resolved, filepath)
15
+ # @param resolved [Hash] The resolved OpenAPI document.
16
+ # @param filepath [String] The file path of the OpenAPI document.
17
+ def initialize(resolved, filepath = nil)
13
18
  @filepath = filepath
14
19
  @paths = resolved['paths']
15
20
  @openapi_version = detect_version(resolved)
16
21
  end
17
22
 
23
+ # Validates the request against the API description.
24
+ # @param rack_request [Rack::Request] The Rack request object.
25
+ # @param raise_error [Boolean] Whether to raise an error if validation fails.
26
+ # @return [RuntimeRequest] The validated request object.
27
+ def validate_request(rack_request, raise_error: false)
28
+ validated = request(rack_request).tap(&:validate)
29
+ validated.error&.raise! if raise_error
30
+ validated
31
+ end
32
+
33
+ # Validates the response against the API description.
34
+ # @param rack_request [Rack::Request] The Rack request object.
35
+ # @param rack_response [Rack::Response] The Rack response object.
36
+ # @param raise_error [Boolean] Whether to raise an error if validation fails.
37
+ # @return [RuntimeResponse] The validated response object.
38
+ def validate_response(rack_request, rack_response, raise_error: false)
39
+ request(rack_request).validate_response(rack_response, raise_error:)
40
+ end
41
+
42
+ # Builds a RuntimeRequest object based on the Rack request.
43
+ # @param rack_request [Rack::Request] The Rack request object.
44
+ # @return [RuntimeRequest] The RuntimeRequest object.
18
45
  def request(rack_request)
19
46
  path_item, path_params = find_path_item_and_params(rack_request.path)
20
47
  operation = path_item&.operation(rack_request.request_method.downcase)
@@ -26,14 +53,25 @@ module OpenapiFirst
26
53
  )
27
54
  end
28
55
 
56
+ # Builds a RuntimeResponse object based on the Rack request and response.
57
+ # @param rack_request [Rack::Request] The Rack request object.
58
+ # @param rack_response [Rack::Response] The Rack response object.
59
+ # @return [RuntimeResponse] The RuntimeResponse object.
29
60
  def response(rack_request, rack_response)
30
61
  request(rack_request).response(rack_response)
31
62
  end
32
63
 
64
+ # Gets all the operations defined in the API description.
65
+ # @return [Array<Operation>] An array of Operation objects.
33
66
  def operations
34
67
  @operations ||= path_items.flat_map(&:operations)
35
68
  end
36
69
 
70
+ # Gets the PathItem object for the specified path.
71
+ # @param pathname [String] The path template string.
72
+ # @return [PathItem] The PathItem object.
73
+ # Example:
74
+ # definition.path('/pets/{id}')
37
75
  def path(pathname)
38
76
  return unless paths.key?(pathname)
39
77
 
@@ -42,6 +80,8 @@ module OpenapiFirst
42
80
 
43
81
  private
44
82
 
83
+ # Gets all the PathItem objects defined in the API description.
84
+ # @return [Array] An array of PathItem objects.
45
85
  def path_items
46
86
  @path_items ||= paths.flat_map do |path, path_item_object|
47
87
  PathItem.new(path, path_item_object, openapi_version:)
@@ -60,7 +100,7 @@ module OpenapiFirst
60
100
 
61
101
  def search_for_path_item(request_path)
62
102
  paths.find do |path, path_item_object|
63
- template = Mustermann::Template.new(path)
103
+ template = Mustermann.new(path)
64
104
  path_params = template.params(request_path)
65
105
  next unless path_params
66
106
  next unless path_params.size == template.names.size
@@ -29,7 +29,7 @@ module OpenapiFirst
29
29
 
30
30
  # The response status
31
31
  def status
32
- STATUS[failure.error_type] || 400
32
+ STATUS[failure.type] || 400
33
33
  end
34
34
 
35
35
  # Render this error response
@@ -1,10 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiFirst
4
+ # @!visibility private
4
5
  class Error < StandardError; end
6
+ # @!visibility private
5
7
  class ParseError < Error; end
8
+ # @!visibility private
6
9
  class NotFoundError < Error; end
10
+ # @!visibility private
7
11
  class RequestInvalidError < Error; end
12
+ # @!visibility private
8
13
  class ResponseNotFoundError < Error; end
14
+ # @!visibility private
9
15
  class ResponseInvalidError < Error; end
10
16
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiFirst
4
+ # A failure object returned when validation of request or response has failed.
4
5
  class Failure
5
6
  FAILURE = :openapi_first_validation_failure
6
7
 
@@ -29,7 +30,7 @@ module OpenapiFirst
29
30
  )
30
31
  end
31
32
 
32
- # @param type [Symbol] See TYPES.keys
33
+ # @param error_type [Symbol] See TYPES.keys
33
34
  # @param message [String] A generic error message
34
35
  # @param errors [Array<OpenapiFirst::Schema::ValidationError>]
35
36
  def initialize(error_type, message: nil, errors: nil)
@@ -43,13 +44,36 @@ module OpenapiFirst
43
44
  @errors = errors
44
45
  end
45
46
 
46
- attr_reader :error_type, :message, :errors
47
+ # @attr_reader [Symbol] error_type The type of the failure. See TYPES.keys.
48
+ # @alias type error_type
49
+ # Example: :invalid_body
50
+ attr_reader :error_type
51
+ alias type error_type
52
+
53
+ # @attr_reader [String] message A generic error message
54
+ attr_reader :message
55
+
56
+ # @attr_reader [Array<OpenapiFirst::Schema::ValidationError>] errors Schema validation errors
57
+ attr_reader :errors
47
58
 
48
59
  # Raise an exception that fits the failure.
49
60
  def raise!
50
- exception, message_prefix = TYPES.fetch(error_type)
61
+ exception, = TYPES.fetch(error_type)
62
+ raise exception, exception_message
63
+ end
64
+
65
+ def exception_message
66
+ _, message_prefix = TYPES.fetch(error_type)
67
+
68
+ "#{message_prefix} #{@message || generate_message}"
69
+ end
70
+
71
+ private
51
72
 
52
- raise exception, "#{message_prefix} #{@message || errors&.map(&:error)&.join('. ')}"
73
+ def generate_message
74
+ messages = errors&.take(4)&.map(&:error)
75
+ messages << "... (#{errors.size} errors total)" if errors && errors.size > 4
76
+ messages&.join('. ')
53
77
  end
54
78
  end
55
79
  end
@@ -26,11 +26,8 @@ module OpenapiFirst
26
26
  request = find_request(env)
27
27
  return @app.call(env) unless request
28
28
 
29
- failure = if @raise
30
- request.validate!
31
- else
32
- request.validate
33
- end
29
+ failure = request.validate
30
+ failure.raise! if failure && @raise
34
31
  return @error_response_class.new(failure:).render if failure
35
32
 
36
33
  @app.call(env)
@@ -20,11 +20,8 @@ module OpenapiFirst
20
20
  def call(env)
21
21
  request = find_request(env)
22
22
  status, headers, body = @app.call(env)
23
-
24
23
  body = body.to_ary if body.respond_to?(:to_ary)
25
-
26
- request.response(Rack::Response[status, headers, body]).validate!
27
-
24
+ request.validate_response(Rack::Response[status, headers, body], raise_error: true)
28
25
  [status, headers, body]
29
26
  end
30
27
 
@@ -29,10 +29,10 @@ module OpenapiFirst
29
29
  MultiJson.dump(result)
30
30
  end
31
31
 
32
- def error_type = failure.error_type
32
+ def type = failure.type
33
33
 
34
34
  def title
35
- TITLES.fetch(error_type)
35
+ TITLES.fetch(type)
36
36
  end
37
37
 
38
38
  def content_type
@@ -51,7 +51,7 @@ module OpenapiFirst
51
51
  end
52
52
 
53
53
  def pointer_key
54
- case error_type
54
+ case type
55
55
  when :invalid_body
56
56
  :pointer
57
57
  when :invalid_query, :invalid_path
@@ -64,7 +64,7 @@ module OpenapiFirst
64
64
  end
65
65
 
66
66
  def pointer(data_pointer)
67
- return data_pointer if error_type == :invalid_body
67
+ return data_pointer if type == :invalid_body
68
68
 
69
69
  data_pointer.delete_prefix('/')
70
70
  end
@@ -4,7 +4,7 @@ require_relative 'default/error_response'
4
4
 
5
5
  module OpenapiFirst
6
6
  module Plugins
7
- module Default
7
+ module Default # :nodoc:
8
8
  OpenapiFirst.register(:default, self)
9
9
  end
10
10
  end
@@ -3,6 +3,7 @@
3
3
  module OpenapiFirst
4
4
  module Plugins
5
5
  module Jsonapi
6
+ # A JSON:API conform error response. See https://jsonapi.org/.
6
7
  class ErrorResponse
7
8
  include OpenapiFirst::ErrorResponse
8
9
 
@@ -36,7 +37,7 @@ module OpenapiFirst
36
37
  end
37
38
 
38
39
  def pointer_key
39
- case failure.error_type
40
+ case failure.type
40
41
  when :invalid_body
41
42
  :pointer
42
43
  when :invalid_query, :invalid_path
@@ -49,7 +50,7 @@ module OpenapiFirst
49
50
  end
50
51
 
51
52
  def pointer(data_pointer)
52
- return data_pointer if failure.error_type == :invalid_body
53
+ return data_pointer if failure.type == :invalid_body
53
54
 
54
55
  data_pointer.delete_prefix('/')
55
56
  end
@@ -4,7 +4,7 @@ require_relative 'jsonapi/error_response'
4
4
 
5
5
  module OpenapiFirst
6
6
  module Plugins
7
- module Jsonapi
7
+ module Jsonapi # :nodoc:
8
8
  OpenapiFirst.register(:jsonapi, self)
9
9
  end
10
10
  end
@@ -4,6 +4,7 @@ module OpenapiFirst
4
4
  # Plugin System adapted from
5
5
  # Polished Ruby Programming by Jeremy Evans
6
6
  # https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewBook?id=0
7
+ # @!visibility private
7
8
  module Plugins
8
9
  PLUGINS = {} # rubocop:disable Style/MutableConstant
9
10
 
@@ -4,7 +4,7 @@ require_relative '../failure'
4
4
 
5
5
  module OpenapiFirst
6
6
  module RequestValidation
7
- class RequestBodyValidator
7
+ class RequestBodyValidator # :nodoc:
8
8
  def initialize(operation)
9
9
  @operation = operation
10
10
  end
@@ -5,6 +5,7 @@ require_relative 'request_body_validator'
5
5
 
6
6
  module OpenapiFirst
7
7
  module RequestValidation
8
+ # Validates a RuntimeRequest against an Operation.
8
9
  class Validator
9
10
  def initialize(operation)
10
11
  @operation = operation
@@ -4,6 +4,7 @@ require_relative '../failure'
4
4
 
5
5
  module OpenapiFirst
6
6
  module ResponseValidation
7
+ # Validates a RuntimeResponse against an Operation.
7
8
  class Validator
8
9
  def initialize(operation)
9
10
  @operation = operation