rswag-specs 2.15.0 → 3.0.0.pre
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/Rakefile +2 -0
- data/lib/generators/rspec/{swagger_generator.rb → openapi_generator.rb} +1 -1
- data/lib/generators/rspec/templates/spec.rb +1 -1
- data/lib/generators/rswag/specs/install/USAGE +2 -2
- data/lib/generators/rswag/specs/install/install_generator.rb +2 -2
- data/lib/generators/rswag/specs/install/templates/{swagger_helper.rb → openapi_helper.rb} +7 -7
- data/lib/rswag/route_parser.rb +2 -2
- data/lib/rswag/specs/configuration.rb +7 -16
- data/lib/rswag/specs/example_group_helpers.rb +28 -41
- data/lib/rswag/specs/example_helpers.rb +7 -16
- data/lib/rswag/specs/extended_schema.rb +3 -1
- data/lib/rswag/specs/openapi_formatter.rb +292 -0
- data/lib/rswag/specs/railtie.rb +1 -7
- data/lib/rswag/specs/request_factory.rb +114 -151
- data/lib/rswag/specs/response_validator.rb +22 -44
- data/lib/rswag/specs.rb +0 -45
- data/lib/tasks/rswag-specs_tasks.rake +6 -7
- metadata +18 -17
- data/lib/rswag/specs/swagger_formatter.rb +0 -229
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require 'active_support'
|
3
4
|
require 'active_support/core_ext/hash/slice'
|
4
5
|
require 'active_support/core_ext/hash/conversions'
|
5
6
|
require 'json'
|
@@ -7,217 +8,179 @@ require 'json'
|
|
7
8
|
module Rswag
|
8
9
|
module Specs
|
9
10
|
class RequestFactory
|
10
|
-
|
11
|
+
attr_accessor :example, :metadata, :params, :headers
|
12
|
+
|
13
|
+
def initialize(metadata, example, config = ::Rswag::Specs.config)
|
11
14
|
@config = config
|
15
|
+
@example = example
|
16
|
+
@metadata = metadata
|
17
|
+
@params = example.respond_to?(:request_params) ? example.request_params : {}
|
18
|
+
@headers = example.respond_to?(:request_headers) ? example.request_headers : {}
|
12
19
|
end
|
13
20
|
|
14
|
-
def build_request
|
15
|
-
|
16
|
-
parameters = expand_parameters(metadata,
|
21
|
+
def build_request
|
22
|
+
openapi_spec = @config.get_openapi_spec(metadata[:openapi_spec])
|
23
|
+
parameters = expand_parameters(metadata, openapi_spec, example)
|
17
24
|
|
18
25
|
{}.tap do |request|
|
19
26
|
add_verb(request, metadata)
|
20
|
-
add_path(request, metadata,
|
21
|
-
add_headers(request, metadata,
|
27
|
+
add_path(request, metadata, openapi_spec, parameters, example)
|
28
|
+
add_headers(request, metadata, openapi_spec, parameters, example)
|
22
29
|
add_payload(request, parameters, example)
|
23
30
|
end
|
24
31
|
end
|
25
32
|
|
26
33
|
private
|
27
34
|
|
28
|
-
def expand_parameters(metadata,
|
35
|
+
def expand_parameters(metadata, openapi_spec, _example)
|
29
36
|
operation_params = metadata[:operation][:parameters] || []
|
30
37
|
path_item_params = metadata[:path_item][:parameters] || []
|
31
|
-
security_params = derive_security_params(metadata,
|
38
|
+
security_params = derive_security_params(metadata, openapi_spec)
|
32
39
|
|
33
40
|
# NOTE: Use of + instead of concat to avoid mutation of the metadata object
|
34
41
|
(operation_params + path_item_params + security_params)
|
35
|
-
.map { |p| p['$ref'] ? resolve_parameter(p['$ref'],
|
42
|
+
.map { |p| p['$ref'] ? resolve_parameter(p['$ref'], openapi_spec) : p }
|
36
43
|
.uniq { |p| p[:name] }
|
37
|
-
.reject
|
44
|
+
.reject do |p|
|
45
|
+
p[:required] == false &&
|
46
|
+
!headers.key?(p[:name]) &&
|
47
|
+
!params.key?(p[:name])
|
48
|
+
end
|
38
49
|
end
|
39
50
|
|
40
|
-
def derive_security_params(metadata,
|
41
|
-
requirements = metadata[:operation][:security] ||
|
51
|
+
def derive_security_params(metadata, openapi_spec)
|
52
|
+
requirements = metadata[:operation][:security] || openapi_spec[:security] || []
|
42
53
|
scheme_names = requirements.flat_map(&:keys)
|
43
|
-
schemes = security_version(scheme_names,
|
54
|
+
schemes = security_version(scheme_names, openapi_spec)
|
44
55
|
|
45
56
|
schemes.map do |scheme|
|
46
|
-
param =
|
47
|
-
param.merge(type: :string, required: requirements.one?)
|
57
|
+
param = scheme[:type] == :apiKey ? scheme.slice(:name, :in) : { name: 'Authorization', in: :header }
|
58
|
+
param.merge(schema: { type: :string }, required: requirements.one?)
|
48
59
|
end
|
49
60
|
end
|
50
61
|
|
51
|
-
def security_version(scheme_names,
|
52
|
-
|
53
|
-
|
54
|
-
else # Openapi3
|
55
|
-
if swagger_doc.key?(:securityDefinitions)
|
56
|
-
Rswag::Specs.deprecator.warn('Rswag::Specs: WARNING: securityDefinitions is replaced in OpenAPI3! Rename to components/securitySchemes (in swagger_helper.rb)')
|
57
|
-
swagger_doc[:components] ||= { securitySchemes: swagger_doc[:securityDefinitions] }
|
58
|
-
swagger_doc.delete(:securityDefinitions)
|
59
|
-
end
|
60
|
-
components = swagger_doc[:components] || {}
|
61
|
-
(components[:securitySchemes] || {}).slice(*scheme_names).values
|
62
|
-
end
|
62
|
+
def security_version(scheme_names, openapi_spec)
|
63
|
+
components = openapi_spec[:components] || {}
|
64
|
+
(components[:securitySchemes] || {}).slice(*scheme_names).values
|
63
65
|
end
|
64
66
|
|
65
|
-
def resolve_parameter(ref,
|
66
|
-
key = key_version(ref,
|
67
|
-
definitions = definition_version(
|
67
|
+
def resolve_parameter(ref, openapi_spec)
|
68
|
+
key = key_version(ref, openapi_spec)
|
69
|
+
definitions = definition_version(openapi_spec)
|
68
70
|
raise "Referenced parameter '#{ref}' must be defined" unless definitions && definitions[key]
|
69
71
|
|
70
72
|
definitions[key]
|
71
73
|
end
|
72
74
|
|
73
|
-
def key_version(ref,
|
74
|
-
|
75
|
-
ref.sub('#/parameters/', '').to_sym
|
76
|
-
else # Openapi3
|
77
|
-
if ref.start_with?('#/parameters/')
|
78
|
-
Rswag::Specs.deprecator.warn('Rswag::Specs: WARNING: #/parameters/ refs are replaced in OpenAPI3! Rename to #/components/parameters/')
|
79
|
-
ref.sub('#/parameters/', '').to_sym
|
80
|
-
else
|
81
|
-
ref.sub('#/components/parameters/', '').to_sym
|
82
|
-
end
|
83
|
-
end
|
75
|
+
def key_version(ref, _openapi_spec)
|
76
|
+
ref.sub('#/components/parameters/', '').to_sym
|
84
77
|
end
|
85
78
|
|
86
|
-
def definition_version(
|
87
|
-
|
88
|
-
|
89
|
-
else # Openapi3
|
90
|
-
if swagger_doc.key?(:parameters)
|
91
|
-
Rswag::Specs.deprecator.warn('Rswag::Specs: WARNING: parameters is replaced in OpenAPI3! Rename to components/parameters (in swagger_helper.rb)')
|
92
|
-
swagger_doc[:parameters]
|
93
|
-
else
|
94
|
-
components = swagger_doc[:components] || {}
|
95
|
-
components[:parameters]
|
96
|
-
end
|
97
|
-
end
|
79
|
+
def definition_version(openapi_spec)
|
80
|
+
components = openapi_spec[:components] || {}
|
81
|
+
components[:parameters]
|
98
82
|
end
|
99
83
|
|
100
84
|
def add_verb(request, metadata)
|
101
85
|
request[:verb] = metadata[:operation][:verb]
|
102
86
|
end
|
103
87
|
|
104
|
-
def base_path_from_servers(
|
105
|
-
return '' if
|
106
|
-
|
88
|
+
def base_path_from_servers(openapi_spec, use_server = :default)
|
89
|
+
return '' if openapi_spec[:servers].nil? || openapi_spec[:servers].empty?
|
90
|
+
|
91
|
+
server = openapi_spec[:servers].first
|
107
92
|
variables = {}
|
108
|
-
server.fetch(:variables, {}).each_pair { |k,v| variables[k] = v[use_server] }
|
109
|
-
base_path = server[:url].gsub(/\{(.*?)\}/) { variables[
|
93
|
+
server.fetch(:variables, {}).each_pair { |k, v| variables[k] = v[use_server] }
|
94
|
+
base_path = server[:url].gsub(/\{(.*?)\}/) { variables[::Regexp.last_match(1).to_sym] }
|
110
95
|
URI(base_path).path
|
111
96
|
end
|
112
97
|
|
113
|
-
def add_path(request, metadata,
|
114
|
-
|
115
|
-
uses_base_path = swagger_doc[:basePath].present?
|
116
|
-
|
117
|
-
if open_api_3_doc && uses_base_path
|
118
|
-
Rswag::Specs.deprecator.warn('Rswag::Specs: WARNING: basePath is replaced in OpenAPI3! Update your swagger_helper.rb')
|
119
|
-
end
|
120
|
-
|
121
|
-
if uses_base_path
|
122
|
-
template = (swagger_doc[:basePath] || '') + metadata[:path_item][:template]
|
123
|
-
else # OpenAPI 3
|
124
|
-
template = base_path_from_servers(swagger_doc) + metadata[:path_item][:template]
|
125
|
-
end
|
98
|
+
def add_path(request, metadata, openapi_spec, parameters, _example)
|
99
|
+
template = base_path_from_servers(openapi_spec) + metadata[:path_item][:template]
|
126
100
|
|
127
101
|
request[:path] = template.tap do |path_template|
|
128
102
|
parameters.select { |p| p[:in] == :path }.each do |p|
|
129
|
-
|
130
|
-
|
131
|
-
|
103
|
+
begin
|
104
|
+
param_value = params.fetch(p[:name].to_s).to_s
|
105
|
+
rescue KeyError
|
106
|
+
raise ArgumentError, ("`#{p[:name]}`" \
|
107
|
+
'parameter key present, but not defined within example group' \
|
108
|
+
'(i. e `it` or `let` block)')
|
132
109
|
end
|
133
|
-
path_template.gsub!("{#{p[:name]}}",
|
110
|
+
path_template.gsub!("{#{p[:name]}}", param_value)
|
134
111
|
end
|
135
112
|
|
136
|
-
parameters.select { |p| p[:in] == :query }.each_with_index do |p, i|
|
113
|
+
parameters.select { |p| p[:in] == :query && params.key?(p[:name]) }.each_with_index do |p, i|
|
137
114
|
path_template.concat(i.zero? ? '?' : '&')
|
138
|
-
path_template.concat(build_query_string_part(p,
|
115
|
+
path_template.concat(build_query_string_part(p, params.fetch(p[:name]), openapi_spec))
|
139
116
|
end
|
140
117
|
end
|
141
118
|
end
|
142
119
|
|
143
|
-
def build_query_string_part(param, value,
|
120
|
+
def build_query_string_part(param, value, _openapi_spec)
|
121
|
+
raise ArgumentError, "'type' is not supported field for Parameter" unless param[:type].nil?
|
122
|
+
|
144
123
|
name = param[:name]
|
145
124
|
escaped_name = CGI.escape(name.to_s)
|
146
125
|
|
147
|
-
#
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
separator = case style
|
170
|
-
when :form then ','
|
171
|
-
when :spaceDelimited then '%20'
|
172
|
-
when :pipeDelimited then '|'
|
173
|
-
end
|
174
|
-
return "#{escaped_name}=" + value.to_a.flatten.map{|v| CGI.escape(v.to_s) }.join(separator)
|
175
|
-
end
|
126
|
+
# NOTE: https://swagger.io/docs/specification/serialization/
|
127
|
+
return unless param[:schema]
|
128
|
+
|
129
|
+
style = param[:style]&.to_sym || :form
|
130
|
+
explode = param[:explode].nil? || param[:explode]
|
131
|
+
type = param.dig(:schema, :type)&.to_sym
|
132
|
+
|
133
|
+
case type
|
134
|
+
when :object
|
135
|
+
case style
|
136
|
+
when :deepObject
|
137
|
+
{ name => value }.to_query
|
138
|
+
when :form
|
139
|
+
return value.to_query if explode
|
140
|
+
|
141
|
+
"#{escaped_name}=" + value.to_a.flatten.map { |v| CGI.escape(v.to_s) }.join(',')
|
142
|
+
|
143
|
+
end
|
144
|
+
when :array
|
145
|
+
case explode
|
146
|
+
when true
|
147
|
+
value.to_a.flatten.map { |v| "#{escaped_name}=#{CGI.escape(v.to_s)}" }.join('&')
|
176
148
|
else
|
177
|
-
|
149
|
+
separator = case style
|
150
|
+
when :form then ','
|
151
|
+
when :spaceDelimited then '%20'
|
152
|
+
when :pipeDelimited then '|'
|
153
|
+
end
|
154
|
+
"#{escaped_name}=" + value.to_a.flatten.map { |v| CGI.escape(v.to_s) }.join(separator)
|
178
155
|
end
|
179
|
-
end
|
180
|
-
|
181
|
-
type = param[:type] || param.dig(:schema, :type)
|
182
|
-
return "#{escaped_name}=#{CGI.escape(value.to_s)}" unless type&.to_sym == :array
|
183
|
-
|
184
|
-
case param[:collectionFormat]
|
185
|
-
when :ssv
|
186
|
-
"#{name}=#{value.join(' ')}"
|
187
|
-
when :tsv
|
188
|
-
"#{name}=#{value.join('\t')}"
|
189
|
-
when :pipes
|
190
|
-
"#{name}=#{value.join('|')}"
|
191
|
-
when :multi
|
192
|
-
value.map { |v| "#{name}=#{v}" }.join('&')
|
193
156
|
else
|
194
|
-
"#{
|
157
|
+
"#{escaped_name}=#{CGI.escape(value.to_s)}"
|
195
158
|
end
|
196
159
|
end
|
197
160
|
|
198
|
-
def add_headers(request, metadata,
|
161
|
+
def add_headers(request, metadata, openapi_spec, parameters, example)
|
199
162
|
tuples = parameters
|
200
|
-
|
201
|
-
|
163
|
+
.select { |p| p[:in] == :header }
|
164
|
+
.map { |p| [p[:name], headers.fetch(p[:name]).to_s] }
|
202
165
|
|
203
166
|
# Accept header
|
204
|
-
produces = metadata[:operation][:produces] ||
|
167
|
+
produces = metadata[:operation][:produces] || openapi_spec[:produces]
|
205
168
|
if produces
|
206
|
-
accept =
|
169
|
+
accept = headers.fetch('Accept', produces.first)
|
207
170
|
tuples << ['Accept', accept]
|
208
171
|
end
|
209
172
|
|
210
173
|
# Content-Type header
|
211
|
-
consumes = metadata[:operation][:consumes] ||
|
174
|
+
consumes = metadata[:operation][:consumes] || openapi_spec[:consumes]
|
212
175
|
if consumes
|
213
|
-
content_type =
|
176
|
+
content_type = headers.fetch('Content-Type', consumes.first)
|
214
177
|
tuples << ['Content-Type', content_type]
|
215
178
|
end
|
216
179
|
|
217
180
|
# Host header
|
218
|
-
host = metadata[:operation][:host] ||
|
181
|
+
host = metadata[:operation][:host] || openapi_spec[:host]
|
219
182
|
if host.present?
|
220
|
-
host = example.respond_to?(:
|
183
|
+
host = example.respond_to?(:Host) ? example.send(:Host) : host
|
221
184
|
tuples << ['Host', host]
|
222
185
|
end
|
223
186
|
|
@@ -225,11 +188,11 @@ module Rswag
|
|
225
188
|
rack_formatted_tuples = tuples.map do |pair|
|
226
189
|
[
|
227
190
|
case pair[0]
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
191
|
+
when 'Accept' then 'HTTP_ACCEPT'
|
192
|
+
when 'Content-Type' then 'CONTENT_TYPE'
|
193
|
+
when 'Authorization' then 'HTTP_AUTHORIZATION'
|
194
|
+
when 'Host' then 'HTTP_HOST'
|
195
|
+
else pair[0]
|
233
196
|
end,
|
234
197
|
pair[1]
|
235
198
|
]
|
@@ -244,31 +207,35 @@ module Rswag
|
|
244
207
|
|
245
208
|
request[:payload] = if ['application/x-www-form-urlencoded', 'multipart/form-data'].include?(content_type)
|
246
209
|
build_form_payload(parameters, example)
|
247
|
-
elsif
|
210
|
+
elsif %r{\Aapplication/([0-9A-Za-z._-]+\+json\z|json\z)}.match?(content_type)
|
248
211
|
build_json_payload(parameters, example)
|
249
212
|
else
|
250
213
|
build_raw_payload(parameters, example)
|
251
214
|
end
|
252
215
|
end
|
253
216
|
|
254
|
-
def build_form_payload(parameters,
|
217
|
+
def build_form_payload(parameters, _example)
|
255
218
|
# See http://seejohncode.com/2012/04/29/quick-tip-testing-multipart-uploads-with-rspec/
|
256
219
|
# Rather that serializing with the appropriate encoding (e.g. multipart/form-data),
|
257
220
|
# Rails test infrastructure allows us to send the values directly as a hash
|
258
221
|
# PROS: simple to implement, CONS: serialization/deserialization is bypassed in test
|
259
222
|
tuples = parameters
|
260
|
-
|
261
|
-
|
223
|
+
.select { |p| p[:in] == :formData }
|
224
|
+
.map { |p| [p[:name], params.fetch(p[:name])] }
|
262
225
|
Hash[tuples]
|
263
226
|
end
|
264
227
|
|
265
|
-
def build_raw_payload(parameters,
|
266
|
-
body_param = parameters.
|
228
|
+
def build_raw_payload(parameters, _example)
|
229
|
+
body_param = parameters.find { |p| p[:in] == :body }
|
267
230
|
return nil unless body_param
|
268
231
|
|
269
|
-
|
232
|
+
begin
|
233
|
+
json_payload = params.fetch(body_param[:name].to_s)
|
234
|
+
rescue KeyError
|
235
|
+
raise(MissingParameterError, body_param[:name])
|
236
|
+
end
|
270
237
|
|
271
|
-
|
238
|
+
json_payload
|
272
239
|
end
|
273
240
|
|
274
241
|
def build_json_payload(parameters, example)
|
@@ -276,11 +243,7 @@ module Rswag
|
|
276
243
|
end
|
277
244
|
|
278
245
|
def doc_version(doc)
|
279
|
-
doc[:openapi]
|
280
|
-
end
|
281
|
-
|
282
|
-
def extract_getter(parameter)
|
283
|
-
parameter[:getter] || parameter[:name]
|
246
|
+
doc[:openapi]
|
284
247
|
end
|
285
248
|
end
|
286
249
|
|
@@ -13,54 +13,55 @@ module Rswag
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def validate!(metadata, response)
|
16
|
-
|
16
|
+
openapi_spec = @config.get_openapi_spec(metadata[:openapi_spec])
|
17
17
|
|
18
18
|
validate_code!(metadata, response)
|
19
19
|
validate_headers!(metadata, response.headers)
|
20
|
-
validate_body!(metadata,
|
20
|
+
validate_body!(metadata, openapi_spec, response.body)
|
21
21
|
end
|
22
22
|
|
23
23
|
private
|
24
24
|
|
25
25
|
def validate_code!(metadata, response)
|
26
26
|
expected = metadata[:response][:code].to_s
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
"
|
31
|
-
|
27
|
+
return unless response.code != expected
|
28
|
+
|
29
|
+
raise UnexpectedResponse,
|
30
|
+
"Expected response code '#{response.code}' to match '#{expected}'\n" \
|
31
|
+
"Response body: #{response.body}"
|
32
32
|
end
|
33
33
|
|
34
34
|
def validate_headers!(metadata, headers)
|
35
|
-
header_schemas =
|
35
|
+
header_schemas = metadata[:response][:headers] || {}
|
36
36
|
expected = header_schemas.keys
|
37
37
|
expected.each do |name|
|
38
38
|
nullable_attribute = header_schemas.dig(name.to_s, :schema, :nullable)
|
39
39
|
required_attribute = header_schemas.dig(name.to_s, :required)
|
40
40
|
|
41
41
|
is_nullable = nullable_attribute.nil? ? false : nullable_attribute
|
42
|
-
is_required = required_attribute.nil?
|
42
|
+
is_required = required_attribute.nil? || required_attribute
|
43
43
|
|
44
|
-
if headers.
|
45
|
-
raise UnexpectedResponse,
|
44
|
+
if !headers.include?(name.to_s) && is_required
|
45
|
+
raise UnexpectedResponse,
|
46
|
+
"Expected response header #{name} to be present"
|
46
47
|
end
|
47
48
|
|
48
49
|
if headers.include?(name.to_s) && headers[name.to_s].nil? && !is_nullable
|
49
|
-
raise UnexpectedResponse,
|
50
|
+
raise UnexpectedResponse,
|
51
|
+
"Expected response header #{name} to not be null"
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
54
|
-
def validate_body!(metadata,
|
56
|
+
def validate_body!(metadata, openapi_spec, body)
|
55
57
|
response_schema = metadata[:response][:schema]
|
56
58
|
return if response_schema.nil?
|
57
59
|
|
58
|
-
|
59
|
-
schemas = definitions_or_component_schemas(swagger_doc, version)
|
60
|
+
schemas = { components: openapi_spec[:components] }
|
60
61
|
|
61
62
|
validation_schema = response_schema
|
62
|
-
|
63
|
-
|
63
|
+
.merge('$schema' => 'http://tempuri.org/rswag/specs/extended_schema')
|
64
|
+
.merge(schemas)
|
64
65
|
|
65
66
|
validation_options = validation_options_from(metadata)
|
66
67
|
|
@@ -73,39 +74,16 @@ module Rswag
|
|
73
74
|
end
|
74
75
|
|
75
76
|
def validation_options_from(metadata)
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
is_strict = !!metadata[:swagger_strict_schema_validation]
|
81
|
-
elsif metadata.key?(:openapi_strict_schema_validation)
|
82
|
-
Rswag::Specs.deprecator.warn('Rswag::Specs: WARNING: This option will be removed in v3.0 please use openapi_all_properties_required and openapi_no_additional_properties set to true')
|
83
|
-
is_strict = !!metadata[:openapi_strict_schema_validation]
|
84
|
-
end
|
85
|
-
|
86
|
-
all_properties_required = metadata.fetch(:openapi_all_properties_required, @config.openapi_all_properties_required)
|
87
|
-
no_additional_properties = metadata.fetch(:openapi_no_additional_properties, @config.openapi_no_additional_properties)
|
77
|
+
all_properties_required = metadata.fetch(:openapi_all_properties_required,
|
78
|
+
@config.openapi_all_properties_required)
|
79
|
+
no_additional_properties = metadata.fetch(:openapi_no_additional_properties,
|
80
|
+
@config.openapi_no_additional_properties)
|
88
81
|
|
89
82
|
{
|
90
|
-
strict: is_strict,
|
91
83
|
allPropertiesRequired: all_properties_required,
|
92
84
|
noAdditionalProperties: no_additional_properties
|
93
85
|
}
|
94
86
|
end
|
95
|
-
|
96
|
-
def definitions_or_component_schemas(swagger_doc, version)
|
97
|
-
if version.start_with?('2')
|
98
|
-
swagger_doc.slice(:definitions)
|
99
|
-
else # Openapi3
|
100
|
-
if swagger_doc.key?(:definitions)
|
101
|
-
Rswag::Specs.deprecator.warn('Rswag::Specs: WARNING: definitions is replaced in OpenAPI3! Rename to components/schemas (in swagger_helper.rb)')
|
102
|
-
swagger_doc.slice(:definitions)
|
103
|
-
else
|
104
|
-
components = swagger_doc[:components] || {}
|
105
|
-
{ components: components }
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
87
|
end
|
110
88
|
|
111
89
|
class UnexpectedResponse < StandardError; end
|
data/lib/rswag/specs.rb
CHANGED
@@ -8,21 +8,12 @@ require 'rswag/specs/railtie' if defined?(Rails::Railtie)
|
|
8
8
|
|
9
9
|
module Rswag
|
10
10
|
module Specs
|
11
|
-
RENAMED_METHODS = {
|
12
|
-
swagger_root: :openapi_root,
|
13
|
-
swagger_docs: :openapi_specs,
|
14
|
-
swagger_dry_run: :rswag_dry_run,
|
15
|
-
swagger_format: :openapi_format
|
16
|
-
}.freeze
|
17
|
-
private_constant :RENAMED_METHODS
|
18
|
-
|
19
11
|
# Extend RSpec with a swagger-based DSL
|
20
12
|
::RSpec.configure do |c|
|
21
13
|
c.add_setting :openapi_root
|
22
14
|
c.add_setting :openapi_specs
|
23
15
|
c.add_setting :rswag_dry_run
|
24
16
|
c.add_setting :openapi_format, default: :json
|
25
|
-
c.add_setting :openapi_strict_schema_validation
|
26
17
|
c.add_setting :openapi_all_properties_required
|
27
18
|
c.add_setting :openapi_no_additional_properties
|
28
19
|
c.extend ExampleGroupHelpers, type: :request
|
@@ -32,41 +23,5 @@ module Rswag
|
|
32
23
|
def self.config
|
33
24
|
@config ||= Configuration.new(RSpec.configuration)
|
34
25
|
end
|
35
|
-
|
36
|
-
def self.deprecator
|
37
|
-
@deprecator ||= ActiveSupport::Deprecation.new('3.0', 'rswag-specs')
|
38
|
-
end
|
39
|
-
|
40
|
-
# Support Rails 3+ and RSpec 2+ (sigh!)
|
41
|
-
RAILS_VERSION = Rails::VERSION::MAJOR
|
42
|
-
RSPEC_VERSION = RSpec::Core::Version::STRING.split('.').first.to_i
|
43
|
-
|
44
|
-
RSpec::Core::Configuration.class_eval do
|
45
|
-
RENAMED_METHODS.each do |old_name, new_name|
|
46
|
-
define_method("#{old_name}=") do |*args, &block|
|
47
|
-
public_send("#{new_name}=", *args, &block)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
define_method('swagger_strict_schema_validation=') do |*args, &block|
|
52
|
-
public_send('openapi_strict_schema_validation=', *args, &block)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
Specs.deprecator.deprecate_methods(
|
57
|
-
RSpec::Core::Configuration,
|
58
|
-
RENAMED_METHODS.to_h { |old_name, new_name| ["#{old_name}=".to_sym, "#{new_name}=".to_sym] }
|
59
|
-
)
|
60
|
-
|
61
|
-
Specs.deprecator.deprecate_methods(
|
62
|
-
RSpec::Core::Configuration,
|
63
|
-
:openapi_strict_schema_validation= => 'use openapi_all_properties_required and openapi_no_additional_properties set to true'
|
64
|
-
)
|
65
|
-
|
66
|
-
if RUBY_VERSION.start_with? '2.6'
|
67
|
-
Specs.deprecator.warn('Rswag::Specs: WARNING: Support for Ruby 2.6 will be dropped in v3.0')
|
68
|
-
end
|
69
|
-
|
70
|
-
Specs.deprecator.warn('Rswag::Specs: WARNING: Support for RSpec 2.X will be dropped in v3.0') if RSPEC_VERSION < 3
|
71
26
|
end
|
72
27
|
end
|
@@ -4,7 +4,7 @@ require 'rspec/core/rake_task'
|
|
4
4
|
|
5
5
|
namespace :rswag do
|
6
6
|
namespace :specs do
|
7
|
-
desc 'Generate
|
7
|
+
desc 'Generate OpenAPI JSON files from integration specs'
|
8
8
|
RSpec::Core::RakeTask.new('swaggerize') do |t|
|
9
9
|
t.pattern = ENV.fetch(
|
10
10
|
'PATTERN',
|
@@ -16,13 +16,12 @@ namespace :rswag do
|
|
16
16
|
''
|
17
17
|
)
|
18
18
|
|
19
|
-
t.rspec_opts = [
|
19
|
+
t.rspec_opts = [
|
20
|
+
'--format Rswag::Specs::OpenapiFormatter',
|
21
|
+
'--order defined'
|
22
|
+
] << additional_rspec_opts
|
20
23
|
|
21
|
-
if Rswag::Specs.config.rswag_dry_run
|
22
|
-
t.rspec_opts += ['--format Rswag::Specs::SwaggerFormatter', '--dry-run', '--order defined']
|
23
|
-
else
|
24
|
-
t.rspec_opts += ['--format Rswag::Specs::SwaggerFormatter', '--order defined']
|
25
|
-
end
|
24
|
+
t.rspec_opts += ['--dry-run'] if Rswag::Specs.config.rswag_dry_run
|
26
25
|
end
|
27
26
|
end
|
28
27
|
end
|