openapi_first 1.2.1 → 1.3.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.
- checksums.yaml +4 -4
- data/lib/openapi_first/body_parser.rb +1 -0
- data/lib/openapi_first/configuration.rb +3 -1
- data/lib/openapi_first/definition/operation.rb +66 -5
- data/lib/openapi_first/definition/path_item.rb +1 -0
- data/lib/openapi_first/definition/request_body.rb +2 -1
- data/lib/openapi_first/definition/response.rb +7 -0
- data/lib/openapi_first/definition.rb +40 -0
- data/lib/openapi_first/error_response.rb +1 -1
- data/lib/openapi_first/errors.rb +6 -0
- data/lib/openapi_first/failure.rb +13 -2
- data/lib/openapi_first/middlewares/request_validation.rb +2 -5
- data/lib/openapi_first/middlewares/response_validation.rb +1 -4
- data/lib/openapi_first/plugins/default/error_response.rb +4 -4
- data/lib/openapi_first/plugins/default.rb +1 -1
- data/lib/openapi_first/plugins/jsonapi/error_response.rb +3 -2
- data/lib/openapi_first/plugins/jsonapi.rb +1 -1
- data/lib/openapi_first/plugins.rb +1 -0
- data/lib/openapi_first/request_validation/request_body_validator.rb +1 -1
- data/lib/openapi_first/request_validation/validator.rb +1 -0
- data/lib/openapi_first/response_validation/validator.rb +1 -0
- data/lib/openapi_first/runtime_request.rb +63 -3
- data/lib/openapi_first/runtime_response.rb +43 -4
- data/lib/openapi_first/schema/validation_error.rb +2 -0
- data/lib/openapi_first/schema/validation_result.rb +2 -0
- data/lib/openapi_first/schema.rb +1 -0
- data/lib/openapi_first/version.rb +1 -1
- data/lib/openapi_first.rb +8 -0
- metadata +5 -16
- data/.github/CODEOWNERS +0 -1
- data/.github/workflows/ruby.yml +0 -13
- data/.gitignore +0 -11
- data/CHANGELOG.md +0 -279
- data/Gemfile +0 -18
- data/Gemfile.lock +0 -166
- data/Gemfile.rack2 +0 -15
- data/Gemfile.rack2.lock +0 -95
- data/LICENSE.txt +0 -21
- data/README.md +0 -225
- data/openapi_first.gemspec +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7e9e0bad95211ba2b4f103089abc40d0e7fc46a24f7ce8e57318ba489655637
|
4
|
+
data.tar.gz: f1d28fbaa79a4eb7e00b242eb9bd89a78789bbb04742e0b87501ac454fb1cf47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f225e3a49d7f582e0f82822b2c9acbcd6008b6cc2464971e1485ef75ec12e508effc2165b6afc91535e27bc9bb9004f92fb160218f7295b0f45c3f58946ed616
|
7
|
+
data.tar.gz: 4c6ef209df4816361bed148f33b4e55ace50a5481172913c5760d014b09247adf74ffdbd2422ae930cd889494fe941c20d492835863d52a9dde67a75c1bd8622
|
@@ -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
|
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,14 +8,15 @@ 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
18
|
:[]
|
15
19
|
|
16
|
-
WRITE_METHODS = Set.new(%w[post put patch delete]).freeze
|
17
|
-
private_constant :WRITE_METHODS
|
18
|
-
|
19
20
|
def initialize(path, request_method, path_item_object, openapi_version:)
|
20
21
|
@path = path
|
21
22
|
@method = request_method
|
@@ -24,31 +25,63 @@ module OpenapiFirst
|
|
24
25
|
@operation_object = @path_item_object[request_method]
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
|
+
# Returns the path of the operation as in the API description.
|
29
|
+
# @return [String] The path of the operation.
|
30
|
+
attr_reader :path
|
31
|
+
|
32
|
+
# Returns the (downcased) request method of the operation.
|
33
|
+
# Example: "get"
|
34
|
+
# @return [String] The request method of the operation.
|
35
|
+
attr_reader :method
|
28
36
|
alias request_method method
|
29
37
|
|
38
|
+
attr_reader :openapi_version # :nodoc:
|
39
|
+
|
40
|
+
# Returns the operation ID as defined in the API description.
|
41
|
+
# @return [String, nil]
|
30
42
|
def operation_id
|
31
43
|
operation_object['operationId']
|
32
44
|
end
|
33
45
|
|
46
|
+
# Checks if the operation is a read operation.
|
47
|
+
# This is the case for all request methods except POST, PUT, PATCH and DELETE.
|
48
|
+
# @return [Boolean] `true` if the operation is a read operation, `false` otherwise.
|
34
49
|
def read?
|
35
50
|
!write?
|
36
51
|
end
|
37
52
|
|
53
|
+
# Checks if the operation is a write operation.
|
54
|
+
# This is the case for POST, PUT, PATCH and DELETE request methods.
|
55
|
+
# @return [Boolean] `true` if the operation is a write operation, `false` otherwise.
|
56
|
+
# @deprecated Use {#write?} instead.
|
38
57
|
def write?
|
39
58
|
WRITE_METHODS.include?(method)
|
40
59
|
end
|
41
60
|
|
61
|
+
# Returns the request body definition if defined in the API description.
|
62
|
+
# @return [RequestBody, nil] The request body of the operation, or `nil` if not present.
|
42
63
|
def request_body
|
43
64
|
@request_body ||= RequestBody.new(operation_object['requestBody'], self) if operation_object['requestBody']
|
44
65
|
end
|
45
66
|
|
67
|
+
# Checks if a response status is defined for this operation.
|
68
|
+
# @param status [Integer, String] The response status to check.
|
69
|
+
# @return [Boolean] `true` if the response status is defined, `false` otherwise.
|
46
70
|
def response_status_defined?(status)
|
47
71
|
responses.status_defined?(status)
|
48
72
|
end
|
49
73
|
|
50
|
-
|
74
|
+
# Returns the response object for a given status.
|
75
|
+
# @param status [Integer, String] The response status.
|
76
|
+
# @param content_type [String] Content-Type of the current response.
|
77
|
+
# @return [Response, nil] The response object for the given status, or `nil` if not found.
|
78
|
+
def response_for(status, content_type)
|
79
|
+
responses.response_for(status, content_type)
|
80
|
+
end
|
51
81
|
|
82
|
+
# Returns the schema for a given content type.
|
83
|
+
# @param content_type [String] The content type.
|
84
|
+
# @return [Schema, nil] The schema for the given content type, or `nil` if not found.
|
52
85
|
def schema_for(content_type)
|
53
86
|
content = @request_body_object['content']
|
54
87
|
return unless content&.any?
|
@@ -59,44 +92,72 @@ module OpenapiFirst
|
|
59
92
|
end
|
60
93
|
end
|
61
94
|
|
95
|
+
# Returns a unique name for this operation. Used for generating error messages.
|
96
|
+
# @visibility private
|
62
97
|
def name
|
63
98
|
@name ||= "#{method.upcase} #{path} (#{operation_id})"
|
64
99
|
end
|
65
100
|
|
101
|
+
# Returns the path parameters of the operation.
|
102
|
+
# @return [Array<Hash>] The path parameters of the operation.
|
66
103
|
def path_parameters
|
67
104
|
all_parameters['path']
|
68
105
|
end
|
69
106
|
|
107
|
+
# Returns the query parameters of the operation.
|
108
|
+
# Returns parameters defined on the path and in the operation.
|
109
|
+
# @return [Array<Hash>] The query parameters of the operation.
|
70
110
|
def query_parameters
|
71
111
|
all_parameters['query']
|
72
112
|
end
|
73
113
|
|
114
|
+
# Returns the header parameters of the operation.
|
115
|
+
# Returns parameters defined on the path and in the operation.
|
116
|
+
# @return [Array<Hash>] The header parameters of the operation.
|
74
117
|
def header_parameters
|
75
118
|
all_parameters['header']
|
76
119
|
end
|
77
120
|
|
121
|
+
# Returns the cookie parameters of the operation.
|
122
|
+
# Returns parameters defined on the path and in the operation.
|
123
|
+
# @return [Array<Hash>] The cookie parameters of the operation.
|
78
124
|
def cookie_parameters
|
79
125
|
all_parameters['cookie']
|
80
126
|
end
|
81
127
|
|
128
|
+
# Returns the schema for the path parameters.
|
129
|
+
# @visibility private
|
130
|
+
# @return [Schema, nil] The schema for the path parameters, or `nil` if not found.
|
82
131
|
def path_parameters_schema
|
83
132
|
@path_parameters_schema ||= build_schema(path_parameters)
|
84
133
|
end
|
85
134
|
|
135
|
+
# Returns the schema for the query parameters.
|
136
|
+
# @visibility private
|
137
|
+
# @return [Schema, nil] The schema for the query parameters, or `nil` if not found.
|
86
138
|
def query_parameters_schema
|
87
139
|
@query_parameters_schema ||= build_schema(query_parameters)
|
88
140
|
end
|
89
141
|
|
142
|
+
# Returns the schema for the header parameters.
|
143
|
+
# @visibility private
|
144
|
+
# @return [Schema, nil] The schema for the header parameters, or `nil` if not found.
|
90
145
|
def header_parameters_schema
|
91
146
|
@header_parameters_schema ||= build_schema(header_parameters)
|
92
147
|
end
|
93
148
|
|
149
|
+
# Returns the schema for the cookie parameters.
|
150
|
+
# @visibility private
|
151
|
+
# @return [Schema, nil] The schema for the cookie parameters, or `nil` if not found.
|
94
152
|
def cookie_parameters_schema
|
95
153
|
@cookie_parameters_schema ||= build_schema(cookie_parameters)
|
96
154
|
end
|
97
155
|
|
98
156
|
private
|
99
157
|
|
158
|
+
WRITE_METHODS = Set.new(%w[post put patch delete]).freeze
|
159
|
+
private_constant :WRITE_METHODS
|
160
|
+
|
100
161
|
IGNORED_HEADERS = Set['Content-Type', 'Accept', 'Authorization'].freeze
|
101
162
|
private_constant :IGNORED_HEADERS
|
102
163
|
|
@@ -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
|
@@ -36,7 +37,7 @@ module OpenapiFirst
|
|
36
37
|
schema_object = media_type['schema']
|
37
38
|
next unless schema_object
|
38
39
|
|
39
|
-
result[type] = Schema.new(schema_object, write:
|
40
|
+
result[type] = Schema.new(schema_object, write: true,
|
40
41
|
openapi_version: @operation.openapi_version)
|
41
42
|
end
|
42
43
|
end
|
@@ -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
|
@@ -3,18 +3,45 @@
|
|
3
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
|
|
15
|
+
# @param resolved [Hash] The resolved OpenAPI document.
|
16
|
+
# @param filepath [String] The file path of the OpenAPI document.
|
12
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:)
|
data/lib/openapi_first/errors.rb
CHANGED
@@ -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
|
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,7 +44,17 @@ module OpenapiFirst
|
|
43
44
|
@errors = errors
|
44
45
|
end
|
45
46
|
|
46
|
-
attr_reader
|
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!
|
@@ -26,11 +26,8 @@ module OpenapiFirst
|
|
26
26
|
request = find_request(env)
|
27
27
|
return @app.call(env) unless request
|
28
28
|
|
29
|
-
failure =
|
30
|
-
|
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
|
32
|
+
def type = failure.type
|
33
33
|
|
34
34
|
def title
|
35
|
-
TITLES.fetch(
|
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
|
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
|
67
|
+
return data_pointer if type == :invalid_body
|
68
68
|
|
69
69
|
data_pointer.delete_prefix('/')
|
70
70
|
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.
|
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.
|
53
|
+
return data_pointer if failure.type == :invalid_body
|
53
54
|
|
54
55
|
data_pointer.delete_prefix('/')
|
55
56
|
end
|
@@ -16,31 +16,59 @@ module OpenapiFirst
|
|
16
16
|
@path_item = path_item
|
17
17
|
@operation = operation
|
18
18
|
@original_path_params = path_params
|
19
|
+
@error = nil
|
20
|
+
@validated = false
|
19
21
|
end
|
20
22
|
|
21
23
|
def_delegators :@request, :content_type, :media_type, :path
|
22
24
|
def_delegators :@operation, :operation_id, :request_method
|
23
25
|
def_delegator :@path_item, :path, :path_definition
|
24
26
|
|
25
|
-
|
27
|
+
# Returns the path_item object.
|
28
|
+
# @return [PathItem, nil] The path_item object or nil if this request path is not known.
|
29
|
+
attr_reader :path_item
|
26
30
|
|
31
|
+
# Returns the operation object.
|
32
|
+
# @return [Operation, nil] The operation object or nil if this request method is not known.
|
33
|
+
attr_reader :operation
|
34
|
+
|
35
|
+
# Returns the error object if validation failed.
|
36
|
+
# @return [Failure, nil]
|
37
|
+
attr_reader :error
|
38
|
+
|
39
|
+
# Checks if the request is valid.
|
40
|
+
# @return [Boolean] true if the request is valid, false otherwise.
|
41
|
+
def valid?
|
42
|
+
validate unless @validated
|
43
|
+
error.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
# Checks if the path and request method are known.
|
47
|
+
# @return [Boolean] true if the path and request method are known, false otherwise.
|
27
48
|
def known?
|
28
49
|
known_path? && known_request_method?
|
29
50
|
end
|
30
51
|
|
52
|
+
# Checks if the path is known.
|
53
|
+
# @return [Boolean] true if the path is known, false otherwise.
|
31
54
|
def known_path?
|
32
55
|
!!path_item
|
33
56
|
end
|
34
57
|
|
58
|
+
# Checks if the request method is known.
|
59
|
+
# @return [Boolean] true if the request method is known, false otherwise.
|
35
60
|
def known_request_method?
|
36
61
|
!!operation
|
37
62
|
end
|
38
63
|
|
39
|
-
#
|
64
|
+
# Returns the merged path and query parameters.
|
65
|
+
# @return [Hash] The merged path and query parameters.
|
40
66
|
def params
|
41
67
|
@params ||= query.merge(path_parameters)
|
42
68
|
end
|
43
69
|
|
70
|
+
# Returns the parsed path parameters of the request.
|
71
|
+
# @return [Hash]
|
44
72
|
def path_parameters
|
45
73
|
return {} unless operation.path_parameters
|
46
74
|
|
@@ -48,6 +76,10 @@ module OpenapiFirst
|
|
48
76
|
OpenapiParameters::Path.new(operation.path_parameters).unpack(@original_path_params) || {}
|
49
77
|
end
|
50
78
|
|
79
|
+
# Returns the parsed query parameters.
|
80
|
+
# This only includes parameters that are defined in the API description.
|
81
|
+
# @note This method is aliased as query_parameters.
|
82
|
+
# @return [Hash]
|
51
83
|
def query
|
52
84
|
return {} unless operation.query_parameters
|
53
85
|
|
@@ -57,12 +89,18 @@ module OpenapiFirst
|
|
57
89
|
|
58
90
|
alias query_parameters query
|
59
91
|
|
92
|
+
# Returns the parsed header parameters.
|
93
|
+
# This only includes parameters that are defined in the API description.
|
94
|
+
# @return [Hash]
|
60
95
|
def headers
|
61
96
|
return {} unless operation.header_parameters
|
62
97
|
|
63
98
|
@headers ||= OpenapiParameters::Header.new(operation.header_parameters).unpack_env(request.env) || {}
|
64
99
|
end
|
65
100
|
|
101
|
+
# Returns the parsed cookie parameters.
|
102
|
+
# This only includes parameters that are defined in the API description.
|
103
|
+
# @return [Hash]
|
66
104
|
def cookies
|
67
105
|
return {} unless operation.cookie_parameters
|
68
106
|
|
@@ -70,20 +108,42 @@ module OpenapiFirst
|
|
70
108
|
OpenapiParameters::Cookie.new(operation.cookie_parameters).unpack(request.env[Rack::HTTP_COOKIE]) || {}
|
71
109
|
end
|
72
110
|
|
111
|
+
# Returns the parsed request body.
|
112
|
+
# This returns the whole request body with default values applied as defined in the API description.
|
113
|
+
# This does not remove any fields that are not defined in the API description.
|
114
|
+
# @return [Hash, Array, String, nil] The parsed body of the request.
|
73
115
|
def body
|
74
116
|
@body ||= BodyParser.new.parse(request, request.media_type)
|
75
117
|
end
|
118
|
+
|
76
119
|
alias parsed_body body
|
77
120
|
|
121
|
+
# Validates the request.
|
122
|
+
# @return [Failure, nil] The Failure object if validation failed.
|
78
123
|
def validate
|
79
|
-
|
124
|
+
@validated = true
|
125
|
+
@error = RequestValidation::Validator.new(operation).validate(self)
|
80
126
|
end
|
81
127
|
|
128
|
+
# Validates the request and raises an error if validation fails.
|
82
129
|
def validate!
|
83
130
|
error = validate
|
84
131
|
error&.raise!
|
85
132
|
end
|
86
133
|
|
134
|
+
# Validates the response.
|
135
|
+
# @param rack_response [Rack::Response] The rack response object.
|
136
|
+
# @param raise_error [Boolean] Whether to raise an error if validation fails.
|
137
|
+
# @return [RuntimeResponse] The validated response object.
|
138
|
+
def validate_response(rack_response, raise_error: false)
|
139
|
+
validated = response(rack_response).tap(&:validate)
|
140
|
+
validated.error&.raise! if raise_error
|
141
|
+
validated
|
142
|
+
end
|
143
|
+
|
144
|
+
# Creates a new RuntimeResponse object.
|
145
|
+
# @param rack_response [Rack::Response] The rack response object.
|
146
|
+
# @return [RuntimeResponse] The RuntimeResponse object.
|
87
147
|
def response(rack_response)
|
88
148
|
RuntimeResponse.new(operation, rack_response)
|
89
149
|
end
|