openapi_first 1.4.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -1
- data/README.md +105 -28
- data/lib/openapi_first/body_parser.rb +8 -11
- data/lib/openapi_first/builder.rb +81 -0
- data/lib/openapi_first/configuration.rb +24 -3
- data/lib/openapi_first/definition.rb +44 -100
- data/lib/openapi_first/error_response.rb +2 -2
- data/lib/openapi_first/error_responses/default.rb +73 -0
- data/lib/openapi_first/error_responses/jsonapi.rb +59 -0
- data/lib/openapi_first/errors.rb +26 -4
- data/lib/openapi_first/failure.rb +29 -26
- data/lib/openapi_first/json_refs.rb +1 -3
- data/lib/openapi_first/middlewares/request_validation.rb +2 -2
- data/lib/openapi_first/middlewares/response_validation.rb +4 -3
- data/lib/openapi_first/request.rb +92 -0
- data/lib/openapi_first/request_parser.rb +35 -0
- data/lib/openapi_first/request_validator.rb +25 -0
- data/lib/openapi_first/response.rb +57 -0
- data/lib/openapi_first/response_parser.rb +49 -0
- data/lib/openapi_first/response_validator.rb +27 -0
- data/lib/openapi_first/router/find_content.rb +17 -0
- data/lib/openapi_first/router/find_response.rb +45 -0
- data/lib/openapi_first/{definition → router}/path_template.rb +9 -1
- data/lib/openapi_first/router.rb +100 -0
- data/lib/openapi_first/schema/validation_error.rb +16 -10
- data/lib/openapi_first/schema/validation_result.rb +8 -6
- data/lib/openapi_first/schema.rb +4 -8
- data/lib/openapi_first/test/methods.rb +21 -0
- data/lib/openapi_first/test.rb +19 -0
- data/lib/openapi_first/validated_request.rb +81 -0
- data/lib/openapi_first/validated_response.rb +33 -0
- data/lib/openapi_first/validators/request_body.rb +39 -0
- data/lib/openapi_first/validators/request_parameters.rb +61 -0
- data/lib/openapi_first/validators/response_body.rb +30 -0
- data/lib/openapi_first/validators/response_headers.rb +25 -0
- data/lib/openapi_first/version.rb +1 -1
- data/lib/openapi_first.rb +40 -21
- metadata +35 -24
- data/lib/openapi_first/definition/operation.rb +0 -197
- data/lib/openapi_first/definition/path_item.rb +0 -40
- data/lib/openapi_first/definition/request_body.rb +0 -46
- data/lib/openapi_first/definition/response.rb +0 -32
- data/lib/openapi_first/definition/responses.rb +0 -87
- data/lib/openapi_first/plugins/default/error_response.rb +0 -74
- data/lib/openapi_first/plugins/default.rb +0 -11
- data/lib/openapi_first/plugins/jsonapi/error_response.rb +0 -60
- data/lib/openapi_first/plugins/jsonapi.rb +0 -11
- data/lib/openapi_first/plugins.rb +0 -25
- data/lib/openapi_first/request_validation/request_body_validator.rb +0 -41
- data/lib/openapi_first/request_validation/validator.rb +0 -82
- data/lib/openapi_first/response_validation/validator.rb +0 -98
- data/lib/openapi_first/runtime_request.rb +0 -166
- data/lib/openapi_first/runtime_response.rb +0 -124
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OpenapiFirst
|
4
|
-
# Plugin System adapted from
|
5
|
-
# Polished Ruby Programming by Jeremy Evans
|
6
|
-
# https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewBook?id=0
|
7
|
-
# @!visibility private
|
8
|
-
module Plugins
|
9
|
-
PLUGINS = {} # rubocop:disable Style/MutableConstant
|
10
|
-
private_constant :PLUGINS
|
11
|
-
|
12
|
-
def register(name, klass)
|
13
|
-
PLUGINS[name.to_sym] = klass
|
14
|
-
end
|
15
|
-
|
16
|
-
def plugin(name)
|
17
|
-
require "openapi_first/plugins/#{name}"
|
18
|
-
PLUGINS.fetch(name.to_sym)
|
19
|
-
end
|
20
|
-
|
21
|
-
def find_plugin(name)
|
22
|
-
PLUGINS.fetch(name)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../failure'
|
4
|
-
|
5
|
-
module OpenapiFirst
|
6
|
-
module RequestValidation
|
7
|
-
class RequestBodyValidator # :nodoc:
|
8
|
-
def initialize(operation)
|
9
|
-
@operation = operation
|
10
|
-
end
|
11
|
-
|
12
|
-
def validate!(parsed_request_body, request_content_type)
|
13
|
-
request_body = operation.request_body
|
14
|
-
schema = request_body.schema_for(request_content_type)
|
15
|
-
unless schema
|
16
|
-
Failure.fail!(:unsupported_media_type,
|
17
|
-
message: "Unsupported Media Type '#{request_content_type}'")
|
18
|
-
end
|
19
|
-
|
20
|
-
if request_body.required? && parsed_request_body.nil?
|
21
|
-
Failure.fail!(:invalid_body,
|
22
|
-
message: 'Request body is not defined')
|
23
|
-
end
|
24
|
-
|
25
|
-
validate_body!(parsed_request_body, schema)
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
attr_reader :operation
|
31
|
-
|
32
|
-
def validate_body!(parsed_request_body, schema)
|
33
|
-
request_body_schema = schema
|
34
|
-
return unless request_body_schema
|
35
|
-
|
36
|
-
validation = request_body_schema.validate(parsed_request_body)
|
37
|
-
Failure.fail!(:invalid_body, errors: validation.errors) if validation.error?
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,82 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../failure'
|
4
|
-
require_relative 'request_body_validator'
|
5
|
-
|
6
|
-
module OpenapiFirst
|
7
|
-
module RequestValidation
|
8
|
-
# Validates a RuntimeRequest against an Operation.
|
9
|
-
class Validator
|
10
|
-
def initialize(operation)
|
11
|
-
@operation = operation
|
12
|
-
end
|
13
|
-
|
14
|
-
def validate(runtime_request)
|
15
|
-
catch Failure::FAILURE do
|
16
|
-
validate_defined(runtime_request)
|
17
|
-
validate_parameters!(runtime_request)
|
18
|
-
validate_request_body!(runtime_request)
|
19
|
-
nil
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
attr_reader :operation, :raw_path_params
|
26
|
-
|
27
|
-
def validate_defined(request)
|
28
|
-
return if request.known?
|
29
|
-
return Failure.fail!(:not_found) unless request.known_path?
|
30
|
-
|
31
|
-
Failure.fail!(:method_not_allowed) unless request.known_request_method?
|
32
|
-
end
|
33
|
-
|
34
|
-
def validate_parameters!(request)
|
35
|
-
validate_query_params!(request)
|
36
|
-
validate_path_params!(request)
|
37
|
-
validate_cookie_params!(request)
|
38
|
-
validate_header_params!(request)
|
39
|
-
end
|
40
|
-
|
41
|
-
def validate_path_params!(request)
|
42
|
-
schema = operation.path_parameters_schema
|
43
|
-
return unless schema
|
44
|
-
|
45
|
-
validation = schema.validate(request.path_parameters)
|
46
|
-
Failure.fail!(:invalid_path, errors: validation.errors) if validation.error?
|
47
|
-
end
|
48
|
-
|
49
|
-
def validate_query_params!(request)
|
50
|
-
schema = operation.query_parameters_schema
|
51
|
-
return unless schema
|
52
|
-
|
53
|
-
validation = schema.validate(request.query)
|
54
|
-
Failure.fail!(:invalid_query, errors: validation.errors) if validation.error?
|
55
|
-
end
|
56
|
-
|
57
|
-
def validate_cookie_params!(request)
|
58
|
-
schema = operation.cookie_parameters_schema
|
59
|
-
return unless schema
|
60
|
-
|
61
|
-
validation = schema.validate(request.cookies)
|
62
|
-
Failure.fail!(:invalid_cookie, errors: validation.errors) if validation.error?
|
63
|
-
end
|
64
|
-
|
65
|
-
def validate_header_params!(request)
|
66
|
-
schema = operation.header_parameters_schema
|
67
|
-
return unless schema
|
68
|
-
|
69
|
-
validation = schema.validate(request.headers)
|
70
|
-
Failure.fail!(:invalid_header, errors: validation.errors) if validation.error?
|
71
|
-
end
|
72
|
-
|
73
|
-
def validate_request_body!(request)
|
74
|
-
return unless operation.request_body
|
75
|
-
|
76
|
-
RequestBodyValidator.new(operation).validate!(request.body, request.content_type)
|
77
|
-
rescue ParseError => e
|
78
|
-
Failure.fail!(:invalid_body, message: e.message)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
@@ -1,98 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../failure'
|
4
|
-
|
5
|
-
module OpenapiFirst
|
6
|
-
module ResponseValidation
|
7
|
-
# Validates a RuntimeResponse against an Operation.
|
8
|
-
class Validator
|
9
|
-
def initialize(operation)
|
10
|
-
@operation = operation
|
11
|
-
end
|
12
|
-
|
13
|
-
def validate(runtime_response)
|
14
|
-
return unless operation
|
15
|
-
|
16
|
-
catch Failure::FAILURE do
|
17
|
-
validate_defined(runtime_response)
|
18
|
-
response_definition = runtime_response.response_definition
|
19
|
-
validate_response_body(response_definition.content_schema, runtime_response)
|
20
|
-
validate_response_headers(response_definition.headers, runtime_response.headers)
|
21
|
-
nil
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
attr_reader :operation
|
28
|
-
|
29
|
-
def validate_defined(runtime_response)
|
30
|
-
return if runtime_response.known?
|
31
|
-
|
32
|
-
unless runtime_response.known_status?
|
33
|
-
message = "Response status '#{runtime_response.status}' not found for '#{runtime_response.name}'"
|
34
|
-
Failure.fail!(:response_not_found, message:)
|
35
|
-
end
|
36
|
-
|
37
|
-
content_type = runtime_response.content_type
|
38
|
-
if content_type.nil? || content_type.empty?
|
39
|
-
message = "Content-Type for '#{runtime_response.name}' must not be empty"
|
40
|
-
Failure.fail!(:invalid_response_header, message:)
|
41
|
-
end
|
42
|
-
|
43
|
-
message = "Content-Type '#{content_type}' is not defined for '#{runtime_response.name}'"
|
44
|
-
Failure.fail!(:invalid_response_header, message:)
|
45
|
-
end
|
46
|
-
|
47
|
-
def validate_response_body(schema, runtime_response)
|
48
|
-
return unless schema
|
49
|
-
|
50
|
-
begin
|
51
|
-
parsed_body = runtime_response.body
|
52
|
-
rescue ParseError => e
|
53
|
-
Failure.fail!(:invalid_response_body, message: e.message)
|
54
|
-
end
|
55
|
-
|
56
|
-
validation = schema.validate(parsed_body)
|
57
|
-
Failure.fail!(:invalid_response_body, errors: validation.errors) if validation.error?
|
58
|
-
end
|
59
|
-
|
60
|
-
def validate_response_headers(response_header_definitions, unpacked_headers)
|
61
|
-
return unless response_header_definitions
|
62
|
-
|
63
|
-
response_header_definitions.each do |name, definition|
|
64
|
-
next if name == 'Content-Type'
|
65
|
-
|
66
|
-
validate_response_header(name, definition, unpacked_headers, openapi_version: operation.openapi_version)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def validate_response_header(name, definition, unpacked_headers, openapi_version:)
|
71
|
-
unless unpacked_headers.key?(name)
|
72
|
-
if definition['required']
|
73
|
-
Failure.fail!(:invalid_response_header,
|
74
|
-
message: "Required response header '#{name}' is missing")
|
75
|
-
end
|
76
|
-
|
77
|
-
return
|
78
|
-
end
|
79
|
-
|
80
|
-
return unless definition.key?('schema')
|
81
|
-
|
82
|
-
validation = Schema.new(definition['schema'], openapi_version:)
|
83
|
-
value = unpacked_headers[name]
|
84
|
-
validation_result = validation.validate(value)
|
85
|
-
return unless validation_result.error?
|
86
|
-
|
87
|
-
Failure.fail!(:invalid_response_header,
|
88
|
-
errors: validation_result.errors)
|
89
|
-
end
|
90
|
-
|
91
|
-
def load_json(string)
|
92
|
-
MultiJson.load(string)
|
93
|
-
rescue MultiJson::ParseError
|
94
|
-
string
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
@@ -1,166 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'forwardable'
|
4
|
-
require 'openapi_parameters'
|
5
|
-
require_relative 'runtime_response'
|
6
|
-
require_relative 'body_parser'
|
7
|
-
require_relative 'request_validation/validator'
|
8
|
-
|
9
|
-
module OpenapiFirst
|
10
|
-
# RuntimeRequest represents how an incoming request (Rack::Request) matches a request definition.
|
11
|
-
class RuntimeRequest
|
12
|
-
extend Forwardable
|
13
|
-
|
14
|
-
def initialize(request:, path_item:, operation:, path_params:)
|
15
|
-
@request = request
|
16
|
-
@path_item = path_item
|
17
|
-
@operation = operation
|
18
|
-
@original_path_params = path_params
|
19
|
-
@validated = false
|
20
|
-
end
|
21
|
-
|
22
|
-
def_delegators :@request, :content_type, :media_type, :path
|
23
|
-
def_delegators :@operation, :operation_id, :request_method
|
24
|
-
def_delegator :@path_item, :path, :path_definition
|
25
|
-
|
26
|
-
# Returns the path_item object.
|
27
|
-
# @return [PathItem, nil] The path_item object or nil if this request path is not known.
|
28
|
-
attr_reader :path_item
|
29
|
-
|
30
|
-
# Returns the operation object.
|
31
|
-
# @return [Operation, nil] The operation object or nil if this request method is not known.
|
32
|
-
attr_reader :operation
|
33
|
-
|
34
|
-
# Returns the error object if validation failed.
|
35
|
-
# @return [Failure, nil]
|
36
|
-
attr_accessor :error
|
37
|
-
|
38
|
-
# Checks if the request is valid.
|
39
|
-
# @return [Boolean] true if the request is valid, false otherwise.
|
40
|
-
def valid?
|
41
|
-
validate unless validated?
|
42
|
-
error.nil?
|
43
|
-
end
|
44
|
-
|
45
|
-
# Checks if the path and request method are known.
|
46
|
-
# @return [Boolean] true if the path and request method are known, false otherwise.
|
47
|
-
def known?
|
48
|
-
known_path? && known_request_method?
|
49
|
-
end
|
50
|
-
|
51
|
-
# Checks if the path is known.
|
52
|
-
# @return [Boolean] true if the path is known, false otherwise.
|
53
|
-
def known_path?
|
54
|
-
!!path_item
|
55
|
-
end
|
56
|
-
|
57
|
-
# Checks if the request method is known.
|
58
|
-
# @return [Boolean] true if the request method is known, false otherwise.
|
59
|
-
def known_request_method?
|
60
|
-
!!operation
|
61
|
-
end
|
62
|
-
|
63
|
-
# Returns the merged path and query parameters.
|
64
|
-
# @return [Hash] The merged path and query parameters.
|
65
|
-
def params
|
66
|
-
@params ||= query.merge(path_parameters)
|
67
|
-
end
|
68
|
-
|
69
|
-
# Returns the parsed path parameters of the request.
|
70
|
-
# @return [Hash]
|
71
|
-
def path_parameters
|
72
|
-
return {} unless operation.path_parameters
|
73
|
-
|
74
|
-
@path_parameters ||=
|
75
|
-
OpenapiParameters::Path.new(operation.path_parameters).unpack(@original_path_params) || {}
|
76
|
-
end
|
77
|
-
|
78
|
-
# Returns the parsed query parameters.
|
79
|
-
# This only includes parameters that are defined in the API description.
|
80
|
-
# @note This method is aliased as query_parameters.
|
81
|
-
# @return [Hash]
|
82
|
-
def query
|
83
|
-
return {} unless operation.query_parameters
|
84
|
-
|
85
|
-
@query ||=
|
86
|
-
OpenapiParameters::Query.new(operation.query_parameters).unpack(request.env[Rack::QUERY_STRING]) || {}
|
87
|
-
end
|
88
|
-
|
89
|
-
alias query_parameters query
|
90
|
-
|
91
|
-
# Returns the parsed header parameters.
|
92
|
-
# This only includes parameters that are defined in the API description.
|
93
|
-
# @return [Hash]
|
94
|
-
def headers
|
95
|
-
return {} unless operation.header_parameters
|
96
|
-
|
97
|
-
@headers ||= OpenapiParameters::Header.new(operation.header_parameters).unpack_env(request.env) || {}
|
98
|
-
end
|
99
|
-
|
100
|
-
# Returns the parsed cookie parameters.
|
101
|
-
# This only includes parameters that are defined in the API description.
|
102
|
-
# @return [Hash]
|
103
|
-
def cookies
|
104
|
-
return {} unless operation.cookie_parameters
|
105
|
-
|
106
|
-
@cookies ||=
|
107
|
-
OpenapiParameters::Cookie.new(operation.cookie_parameters).unpack(request.env[Rack::HTTP_COOKIE]) || {}
|
108
|
-
end
|
109
|
-
|
110
|
-
# Returns the parsed request body.
|
111
|
-
# This returns the whole request body with default values applied as defined in the API description.
|
112
|
-
# This does not remove any fields that are not defined in the API description.
|
113
|
-
# @return [Hash, Array, String, nil] The parsed body of the request.
|
114
|
-
def body
|
115
|
-
@body ||= BodyParser.new.parse(request, request.media_type)
|
116
|
-
end
|
117
|
-
|
118
|
-
alias parsed_body body
|
119
|
-
|
120
|
-
# Validates the request.
|
121
|
-
# @return [Failure, nil] The Failure object if validation failed.
|
122
|
-
# @deprecated Please use {Definition#validate_request} instead
|
123
|
-
def validate
|
124
|
-
warn '[DEPRECATION] `validate` is deprecated. Please use ' \
|
125
|
-
"`OpenapiFirst.load('openapi.yaml').validate_request(rack_request)` instead."
|
126
|
-
@error = RequestValidation::Validator.new(operation).validate(self)
|
127
|
-
end
|
128
|
-
|
129
|
-
# Validates the request and raises an error if validation fails.
|
130
|
-
def validate!
|
131
|
-
warn '[DEPRECATION] `validate!` is deprecated. Please use ' \
|
132
|
-
"`OpenapiFirst.load('openapi.yaml').validate_request(rack_request, raise_error: true)` instead."
|
133
|
-
error = validate
|
134
|
-
error&.raise!
|
135
|
-
end
|
136
|
-
|
137
|
-
# Validates the response.
|
138
|
-
# @param rack_response [Rack::Response] The rack response object.
|
139
|
-
# @param raise_error [Boolean] Whether to raise an error if validation fails.
|
140
|
-
# @return [RuntimeResponse] The validated response object.
|
141
|
-
def validate_response(rack_response, raise_error: false)
|
142
|
-
warn '[DEPRECATION] `validate_response!` is deprecated. Please use ' \
|
143
|
-
"`OpenapiFirst.load('openapi.yaml').validate_response(request, response, raise_error: false)` instead."
|
144
|
-
validated = response(rack_response).tap(&:validate)
|
145
|
-
validated.error&.raise! if raise_error
|
146
|
-
validated
|
147
|
-
end
|
148
|
-
|
149
|
-
# Creates a new RuntimeResponse object.
|
150
|
-
# @param rack_response [Rack::Response] The rack response object.
|
151
|
-
# @return [RuntimeResponse] The RuntimeResponse object.
|
152
|
-
def response(rack_response)
|
153
|
-
warn '[DEPRECATION] `response` is deprecated. Please use ' \
|
154
|
-
"`OpenapiFirst.load('openapi.yaml').validate_response(request, response, raise_error: false)` instead."
|
155
|
-
RuntimeResponse.new(operation, rack_response)
|
156
|
-
end
|
157
|
-
|
158
|
-
private
|
159
|
-
|
160
|
-
def validated?
|
161
|
-
defined?(@error)
|
162
|
-
end
|
163
|
-
|
164
|
-
attr_reader :request
|
165
|
-
end
|
166
|
-
end
|
@@ -1,124 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'forwardable'
|
4
|
-
require_relative 'body_parser'
|
5
|
-
require_relative 'response_validation/validator'
|
6
|
-
|
7
|
-
module OpenapiFirst
|
8
|
-
# Represents a response returned by the Rack application and how it relates to the API description.
|
9
|
-
class RuntimeResponse
|
10
|
-
extend Forwardable
|
11
|
-
|
12
|
-
def initialize(operation, rack_response)
|
13
|
-
@operation = operation
|
14
|
-
@rack_response = rack_response
|
15
|
-
end
|
16
|
-
|
17
|
-
# @return [Failure, nil] Error object if validation failed.
|
18
|
-
attr_accessor :error
|
19
|
-
|
20
|
-
# @visibility private
|
21
|
-
attr_accessor :operation
|
22
|
-
|
23
|
-
# @attr_reader [Integer] status The HTTP status code of this response.
|
24
|
-
# @attr_reader [String] content_type The content_type of the Rack::Response.
|
25
|
-
def_delegators :@rack_response, :status, :content_type
|
26
|
-
|
27
|
-
# @return [String] name The name of the operation. Used for generating error messages.
|
28
|
-
def name
|
29
|
-
"#{@operation.name} response status: #{status}"
|
30
|
-
end
|
31
|
-
|
32
|
-
# Checks if the response is valid. Runs the validation unless it has been run before.
|
33
|
-
# @return [Boolean]
|
34
|
-
def valid?
|
35
|
-
validate unless validated?
|
36
|
-
@error.nil?
|
37
|
-
end
|
38
|
-
|
39
|
-
# Checks if the response is defined in the API description.
|
40
|
-
# @return [Boolean] Returns true if the response is known, false otherwise.
|
41
|
-
def known?
|
42
|
-
!!response_definition
|
43
|
-
end
|
44
|
-
|
45
|
-
# Checks if the response status is defined in the API description.
|
46
|
-
# @return [Boolean] Returns true if the response status is known, false otherwise.
|
47
|
-
def known_status?
|
48
|
-
@operation.response_status_defined?(status)
|
49
|
-
end
|
50
|
-
|
51
|
-
# Returns the description of the response definition if available.
|
52
|
-
# @return [String, nil] Returns the description of the response, or nil if not available.
|
53
|
-
def description
|
54
|
-
response_definition&.description
|
55
|
-
end
|
56
|
-
|
57
|
-
# Returns the parsed (JSON) body of the response.
|
58
|
-
# @return [Hash, String] Returns the body of the response.
|
59
|
-
def body
|
60
|
-
@body ||= content_type =~ /json/i ? load_json(original_body) : original_body
|
61
|
-
end
|
62
|
-
|
63
|
-
# Returns the headers of the response as defined in the API description.
|
64
|
-
# This only returns the headers that are defined in the API description.
|
65
|
-
# @return [Hash] Returns the headers of the response.
|
66
|
-
def headers
|
67
|
-
@headers ||= unpack_response_headers
|
68
|
-
end
|
69
|
-
|
70
|
-
# Validates the response.
|
71
|
-
# @return [Failure, nil] Returns the validation error, or nil if the response is valid.
|
72
|
-
# @deprecated Please use {Definition#validate_response} instead
|
73
|
-
def validate
|
74
|
-
warn '[DEPRECATION] `validate` is deprecated. ' \
|
75
|
-
"Please use `OpenapiFirst.load('openapi.yaml').validate_response(rack_request, rack_response)` instead."
|
76
|
-
@error = ResponseValidation::Validator.new(@operation).validate(self)
|
77
|
-
end
|
78
|
-
|
79
|
-
# Validates the response and raises an error if invalid.
|
80
|
-
# @raise [ResponseNotFoundError, ResponseInvalidError] Raises an error if the response is invalid.
|
81
|
-
def validate!
|
82
|
-
error = validate
|
83
|
-
error&.raise!
|
84
|
-
end
|
85
|
-
|
86
|
-
# Returns the response definition associated with the response.
|
87
|
-
# @return [Definition::Response, nil] Returns the response definition, or nil if not found.
|
88
|
-
def response_definition
|
89
|
-
@response_definition ||= @operation.response_for(status, content_type)
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
93
|
-
|
94
|
-
def validated?
|
95
|
-
defined?(@error)
|
96
|
-
end
|
97
|
-
|
98
|
-
# Usually the body responds to #each, but when using manual response validation without the middleware
|
99
|
-
# in Rails request specs the body is a String. So this code handles both cases.
|
100
|
-
def original_body
|
101
|
-
buffered_body = String.new
|
102
|
-
if @rack_response.body.respond_to?(:each)
|
103
|
-
@rack_response.body.each { |chunk| buffered_body.to_s << chunk }
|
104
|
-
return buffered_body
|
105
|
-
end
|
106
|
-
@rack_response.body
|
107
|
-
end
|
108
|
-
|
109
|
-
def load_json(string)
|
110
|
-
MultiJson.load(string)
|
111
|
-
rescue MultiJson::ParseError
|
112
|
-
raise ParseError, 'Failed to parse response body as JSON'
|
113
|
-
end
|
114
|
-
|
115
|
-
def unpack_response_headers
|
116
|
-
return {} if response_definition&.headers.nil?
|
117
|
-
|
118
|
-
headers_as_parameters = response_definition.headers.map do |name, definition|
|
119
|
-
definition.merge('name' => name, 'in' => 'header')
|
120
|
-
end
|
121
|
-
OpenapiParameters::Header.new(headers_as_parameters).unpack(@rack_response.headers)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|