grape-swagger 0.33.0 → 0.34.2
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/.rubocop.yml +7 -7
- data/.rubocop_todo.yml +0 -6
- data/.travis.yml +10 -11
- data/CHANGELOG.md +72 -6
- data/Gemfile +4 -5
- data/README.md +68 -4
- data/grape-swagger.gemspec +2 -1
- data/lib/grape-swagger/doc_methods/build_model_definition.rb +0 -17
- data/lib/grape-swagger/doc_methods/extensions.rb +6 -1
- data/lib/grape-swagger/doc_methods/format_data.rb +51 -0
- data/lib/grape-swagger/doc_methods/move_params.rb +22 -49
- data/lib/grape-swagger/doc_methods/parse_params.rb +6 -0
- data/lib/grape-swagger/doc_methods.rb +2 -0
- data/lib/grape-swagger/endpoint/params_parser.rb +10 -17
- data/lib/grape-swagger/endpoint.rb +32 -13
- data/lib/grape-swagger/version.rb +1 -1
- data/lib/grape-swagger.rb +1 -1
- data/spec/issues/751_deeply_nested_objects_spec.rb +190 -0
- data/spec/lib/endpoint/params_parser_spec.rb +44 -20
- data/spec/lib/endpoint_spec.rb +3 -3
- data/spec/lib/extensions_spec.rb +10 -0
- data/spec/lib/format_data_spec.rb +91 -0
- data/spec/lib/move_params_spec.rb +4 -266
- data/spec/lib/optional_object_spec.rb +0 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/swagger_v2/api_swagger_v2_hash_and_array_spec.rb +3 -1
- data/spec/swagger_v2/api_swagger_v2_response_with_root_spec.rb +153 -0
- data/spec/swagger_v2/description_not_initialized_spec.rb +39 -0
- data/spec/swagger_v2/endpoint_versioned_path_spec.rb +33 -0
- data/spec/swagger_v2/mounted_target_class_spec.rb +1 -1
- data/spec/swagger_v2/namespace_tags_prefix_spec.rb +15 -1
- data/spec/swagger_v2/params_array_spec.rb +2 -2
- data/spec/swagger_v2/parent_less_namespace_spec.rb +32 -0
- data/spec/swagger_v2/{reference_entity.rb → reference_entity_spec.rb} +17 -10
- metadata +36 -9
- data/spec/swagger_v2/description_not_initialized.rb +0 -39
- data/spec/swagger_v2/parent_less_namespace.rb +0 -49
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrapeSwagger
|
4
|
+
module DocMethods
|
5
|
+
class FormatData
|
6
|
+
class << self
|
7
|
+
def to_format(parameters)
|
8
|
+
parameters.reject { |parameter| parameter[:in] == 'body' }.each do |b|
|
9
|
+
related_parameters = parameters.select do |p|
|
10
|
+
p[:name] != b[:name] && p[:name].to_s.include?(b[:name].to_s.gsub(/\[\]\z/, '') + '[')
|
11
|
+
end
|
12
|
+
parameters.reject! { |p| p[:name] == b[:name] } if move_down(b, related_parameters)
|
13
|
+
end
|
14
|
+
parameters
|
15
|
+
end
|
16
|
+
|
17
|
+
def move_down(parameter, related_parameters)
|
18
|
+
case parameter[:type]
|
19
|
+
when 'array'
|
20
|
+
add_array(parameter, related_parameters)
|
21
|
+
unless related_parameters.blank?
|
22
|
+
add_braces(parameter, related_parameters) if parameter[:name].match?(/\A.*\[\]\z/)
|
23
|
+
return true
|
24
|
+
end
|
25
|
+
when 'object'
|
26
|
+
return true
|
27
|
+
end
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_braces(parameter, related_parameters)
|
32
|
+
param_name = parameter[:name].gsub(/\A(.*)\[\]\z/, '\1')
|
33
|
+
related_parameters.each { |p| p[:name] = p[:name].gsub(param_name, param_name + '[]') }
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_array(parameter, related_parameters)
|
37
|
+
related_parameters.each do |p|
|
38
|
+
p_type = p[:type] == 'array' ? 'string' : p[:type]
|
39
|
+
p[:items] = { type: p_type, format: p[:format], enum: p[:enum], is_array: p[:is_array] }
|
40
|
+
p[:items].delete_if { |_k, v| v.nil? }
|
41
|
+
p[:type] = 'array'
|
42
|
+
p[:is_array] = parameter[:is_array]
|
43
|
+
p.delete(:format)
|
44
|
+
p.delete(:enum)
|
45
|
+
p.delete_if { |_k, v| v.nil? }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -8,7 +8,7 @@ module GrapeSwagger
|
|
8
8
|
class << self
|
9
9
|
attr_accessor :definitions
|
10
10
|
|
11
|
-
def can_be_moved?(
|
11
|
+
def can_be_moved?(http_verb, params)
|
12
12
|
move_methods.include?(http_verb) && includes_body_param?(params)
|
13
13
|
end
|
14
14
|
|
@@ -51,22 +51,33 @@ module GrapeSwagger
|
|
51
51
|
|
52
52
|
def move_params_to_new(definition, params)
|
53
53
|
params, nested_params = params.partition { |x| !x[:name].to_s.include?('[') }
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
add_properties_to_definition(definition,
|
54
|
+
params.each do |param|
|
55
|
+
property = param[:name]
|
56
|
+
param_properties, param_required = build_properties([param])
|
57
|
+
add_properties_to_definition(definition, param_properties, param_required)
|
58
|
+
related_nested_params, nested_params = nested_params.partition { |x| x[:name].start_with?("#{property}[") }
|
59
|
+
prepare_nested_names(property, related_nested_params)
|
60
|
+
|
61
|
+
next if related_nested_params.blank?
|
62
|
+
|
63
|
+
nested_definition = if should_expose_as_array?([param])
|
64
|
+
move_params_to_new(array_type, related_nested_params)
|
65
|
+
else
|
66
|
+
move_params_to_new(object_type, related_nested_params)
|
67
|
+
end
|
68
|
+
if definition.key?(:items)
|
69
|
+
definition[:items][:properties][property.to_sym].deep_merge!(nested_definition)
|
70
|
+
else
|
71
|
+
definition[:properties][property.to_sym].deep_merge!(nested_definition)
|
72
|
+
end
|
58
73
|
end
|
59
|
-
|
60
|
-
nested_properties = build_nested_properties(nested_params) unless nested_params.blank?
|
61
|
-
add_properties_to_definition(definition, nested_properties, []) unless nested_params.blank?
|
74
|
+
definition
|
62
75
|
end
|
63
76
|
|
64
77
|
def build_properties(params)
|
65
78
|
properties = {}
|
66
79
|
required = []
|
67
80
|
|
68
|
-
prepare_nested_types(params) if should_expose_as_array?(params)
|
69
|
-
|
70
81
|
params.each do |param|
|
71
82
|
name = param[:name].to_sym
|
72
83
|
|
@@ -103,28 +114,6 @@ module GrapeSwagger
|
|
103
114
|
end
|
104
115
|
end
|
105
116
|
|
106
|
-
def build_nested_properties(params, properties = {})
|
107
|
-
property = params.bsearch { |x| x[:name].include?('[') }[:name].split('[').first
|
108
|
-
|
109
|
-
nested_params, params = params.partition { |x| x[:name].start_with?("#{property}[") }
|
110
|
-
prepare_nested_names(property, nested_params)
|
111
|
-
|
112
|
-
recursive_call(properties, property, nested_params) unless nested_params.empty?
|
113
|
-
build_nested_properties(params, properties) unless params.empty?
|
114
|
-
|
115
|
-
properties
|
116
|
-
end
|
117
|
-
|
118
|
-
def recursive_call(properties, property, nested_params)
|
119
|
-
if should_expose_as_array?(nested_params)
|
120
|
-
properties[property.to_sym] = array_type
|
121
|
-
move_params_to_new(properties[property.to_sym][:items], nested_params)
|
122
|
-
else
|
123
|
-
properties[property.to_sym] = object_type
|
124
|
-
move_params_to_new(properties[property.to_sym], nested_params)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
117
|
def movable_params(params)
|
129
118
|
to_delete = params.each_with_object([]) { |x, memo| memo << x if deletable?(x) }
|
130
119
|
delete_from(params, to_delete)
|
@@ -177,22 +166,6 @@ module GrapeSwagger
|
|
177
166
|
{ type: 'object', properties: {} }
|
178
167
|
end
|
179
168
|
|
180
|
-
def prepare_nested_types(params)
|
181
|
-
params.each do |param|
|
182
|
-
next unless param[:items]
|
183
|
-
|
184
|
-
param[:type] = if param[:items][:type] == 'array'
|
185
|
-
'string'
|
186
|
-
elsif param[:items].key?('$ref')
|
187
|
-
param[:type] = 'object'
|
188
|
-
else
|
189
|
-
param[:items][:type]
|
190
|
-
end
|
191
|
-
param[:format] = param[:items][:format] if param[:items][:format]
|
192
|
-
param.delete(:items) if param[:type] != 'object'
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
169
|
def prepare_nested_names(property, params)
|
197
170
|
params.each { |x| x[:name] = x[:name].sub(property, '').sub('[', '').sub(']', '') }
|
198
171
|
end
|
@@ -208,7 +181,7 @@ module GrapeSwagger
|
|
208
181
|
end
|
209
182
|
|
210
183
|
def property_keys
|
211
|
-
%i[type format description minimum maximum items enum default]
|
184
|
+
%i[type format description minimum maximum items enum default additionalProperties]
|
212
185
|
end
|
213
186
|
|
214
187
|
def deletable?(param)
|
@@ -25,6 +25,7 @@ module GrapeSwagger
|
|
25
25
|
document_default_value(settings) unless value_type[:is_array]
|
26
26
|
document_range_values(settings) unless value_type[:is_array]
|
27
27
|
document_required(settings)
|
28
|
+
document_additional_properties(settings)
|
28
29
|
|
29
30
|
@parsed_param
|
30
31
|
end
|
@@ -91,6 +92,11 @@ module GrapeSwagger
|
|
91
92
|
@parsed_param[:collectionFormat] = collection_format if DataType.collections.include?(collection_format)
|
92
93
|
end
|
93
94
|
|
95
|
+
def document_additional_properties(settings)
|
96
|
+
additional_properties = settings[:additionalProperties]
|
97
|
+
@parsed_param[:additionalProperties] = additional_properties if additional_properties
|
98
|
+
end
|
99
|
+
|
94
100
|
def param_type(value_type)
|
95
101
|
param_type = value_type[:param_type] || value_type[:in]
|
96
102
|
if value_type[:path].include?("{#{value_type[:param_name]}}")
|
@@ -4,6 +4,7 @@ require 'grape-swagger/doc_methods/status_codes'
|
|
4
4
|
require 'grape-swagger/doc_methods/produces_consumes'
|
5
5
|
require 'grape-swagger/doc_methods/data_type'
|
6
6
|
require 'grape-swagger/doc_methods/extensions'
|
7
|
+
require 'grape-swagger/doc_methods/format_data'
|
7
8
|
require 'grape-swagger/doc_methods/operation_id'
|
8
9
|
require 'grape-swagger/doc_methods/optional_object'
|
9
10
|
require 'grape-swagger/doc_methods/path_string'
|
@@ -102,6 +103,7 @@ module GrapeSwagger
|
|
102
103
|
base_path: nil,
|
103
104
|
add_base_path: false,
|
104
105
|
add_version: true,
|
106
|
+
add_root: false,
|
105
107
|
hide_documentation_path: true,
|
106
108
|
format: :json,
|
107
109
|
authorizations: nil,
|
@@ -15,37 +15,24 @@ module GrapeSwagger
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def parse_request_params
|
18
|
-
array_keys = []
|
19
18
|
public_params.each_with_object({}) do |(name, options), memo|
|
20
19
|
name = name.to_s
|
21
20
|
param_type = options[:type]
|
22
21
|
param_type = param_type.to_s unless param_type.nil?
|
23
22
|
|
24
23
|
if param_type_is_array?(param_type)
|
25
|
-
array_keys << name
|
26
24
|
options[:is_array] = true
|
27
|
-
|
28
|
-
name += '[]' if array_use_braces?(options)
|
29
|
-
else
|
30
|
-
keys = array_keys.find_all { |key| name.start_with? "#{key}[" }
|
31
|
-
if keys.any?
|
32
|
-
options[:is_array] = true
|
33
|
-
if array_use_braces?(options)
|
34
|
-
keys.sort.reverse_each do |key|
|
35
|
-
name = name.sub(key, "#{key}[]")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
25
|
+
name += '[]' if array_use_braces?
|
39
26
|
end
|
40
27
|
|
41
|
-
memo[name] = options
|
28
|
+
memo[name] = options
|
42
29
|
end
|
43
30
|
end
|
44
31
|
|
45
32
|
private
|
46
33
|
|
47
|
-
def array_use_braces?
|
48
|
-
settings[:array_use_braces] && !
|
34
|
+
def array_use_braces?
|
35
|
+
@array_use_braces ||= settings[:array_use_braces] && !includes_body_param?
|
49
36
|
end
|
50
37
|
|
51
38
|
def param_type_is_array?(param_type)
|
@@ -71,6 +58,12 @@ module GrapeSwagger
|
|
71
58
|
param_hidden = param_hidden.call if param_hidden.is_a?(Proc)
|
72
59
|
!param_hidden
|
73
60
|
end
|
61
|
+
|
62
|
+
def includes_body_param?
|
63
|
+
params.any? do |_, options|
|
64
|
+
options.dig(:documentation, :param_type) == 'body' || options.dig(:documentation, :in) == 'body'
|
65
|
+
end
|
66
|
+
end
|
74
67
|
end
|
75
68
|
end
|
76
69
|
end
|
@@ -78,8 +78,7 @@ module Grape
|
|
78
78
|
def path_and_definition_objects(namespace_routes, options)
|
79
79
|
@paths = {}
|
80
80
|
@definitions = {}
|
81
|
-
namespace_routes.
|
82
|
-
routes = namespace_routes[key]
|
81
|
+
namespace_routes.each_value do |routes|
|
83
82
|
path_item(routes, options)
|
84
83
|
end
|
85
84
|
|
@@ -121,7 +120,7 @@ module Grape
|
|
121
120
|
method[:consumes] = consumes_object(route, options[:format])
|
122
121
|
method[:parameters] = params_object(route, options, path)
|
123
122
|
method[:security] = security_object(route)
|
124
|
-
method[:responses] = response_object(route)
|
123
|
+
method[:responses] = response_object(route, options)
|
125
124
|
method[:tags] = route.options.fetch(:tags, tag_object(route, path))
|
126
125
|
method[:operationId] = GrapeSwagger::DocMethods::OperationId.build(route, path)
|
127
126
|
method[:deprecated] = deprecated_object(route)
|
@@ -179,22 +178,24 @@ module Grape
|
|
179
178
|
parameters = partition_params(route, options).map do |param, value|
|
180
179
|
value = { required: false }.merge(value) if value.is_a?(Hash)
|
181
180
|
_, value = default_type([[param, value]]).first if value == ''
|
182
|
-
if value
|
183
|
-
expose_params(value[:type])
|
184
|
-
elsif value[:documentation]
|
181
|
+
if value.dig(:documentation, :type)
|
185
182
|
expose_params(value[:documentation][:type])
|
183
|
+
elsif value[:type]
|
184
|
+
expose_params(value[:type])
|
186
185
|
end
|
187
186
|
GrapeSwagger::DocMethods::ParseParams.call(param, value, path, route, @definitions)
|
188
187
|
end
|
189
188
|
|
190
|
-
if GrapeSwagger::DocMethods::MoveParams.can_be_moved?(
|
189
|
+
if GrapeSwagger::DocMethods::MoveParams.can_be_moved?(route.request_method, parameters)
|
191
190
|
parameters = GrapeSwagger::DocMethods::MoveParams.to_definition(path, parameters, route, @definitions)
|
192
191
|
end
|
193
192
|
|
193
|
+
GrapeSwagger::DocMethods::FormatData.to_format(parameters)
|
194
|
+
|
194
195
|
parameters.presence
|
195
196
|
end
|
196
197
|
|
197
|
-
def response_object(route)
|
198
|
+
def response_object(route, options)
|
198
199
|
codes = http_codes_from_route(route)
|
199
200
|
codes.map! { |x| x.is_a?(Array) ? { code: x[0], message: x[1], model: x[2], examples: x[3], headers: x[4] } : x }
|
200
201
|
|
@@ -219,7 +220,7 @@ module Grape
|
|
219
220
|
|
220
221
|
@definitions[response_model][:description] = description_object(route)
|
221
222
|
|
222
|
-
memo[value[:code]][:schema] = build_reference(route, value, response_model)
|
223
|
+
memo[value[:code]][:schema] = build_reference(route, value, response_model, options)
|
223
224
|
memo[value[:code]][:examples] = value[:examples] if value[:examples]
|
224
225
|
end
|
225
226
|
end
|
@@ -250,20 +251,38 @@ module Grape
|
|
250
251
|
def tag_object(route, path)
|
251
252
|
version = GrapeSwagger::DocMethods::Version.get(route)
|
252
253
|
version = [version] unless version.is_a?(Array)
|
253
|
-
|
254
|
+
prefix = route.prefix.to_s.split('/').reject(&:empty?)
|
254
255
|
Array(
|
255
256
|
path.split('{')[0].split('/').reject(&:empty?).delete_if do |i|
|
256
|
-
|
257
|
+
prefix.include?(i) || version.map(&:to_s).include?(i)
|
257
258
|
end.first
|
258
259
|
).presence
|
259
260
|
end
|
260
261
|
|
261
262
|
private
|
262
263
|
|
263
|
-
def build_reference(route, value, response_model)
|
264
|
+
def build_reference(route, value, response_model, settings)
|
264
265
|
# TODO: proof that the definition exist, if model isn't specified
|
265
266
|
reference = { '$ref' => "#/definitions/#{response_model}" }
|
266
|
-
|
267
|
+
return reference unless value[:code] < 300
|
268
|
+
|
269
|
+
reference = { type: 'array', items: reference } if route.options[:is_array]
|
270
|
+
build_root(route, reference, response_model, settings)
|
271
|
+
end
|
272
|
+
|
273
|
+
def build_root(route, reference, response_model, settings)
|
274
|
+
default_root = response_model.underscore
|
275
|
+
default_root = default_root.pluralize if route.options[:is_array]
|
276
|
+
case route.settings.dig(:swagger, :root)
|
277
|
+
when true
|
278
|
+
{ type: 'object', properties: { default_root => reference } }
|
279
|
+
when false
|
280
|
+
reference
|
281
|
+
when nil
|
282
|
+
settings[:add_root] ? { type: 'object', properties: { default_root => reference } } : reference
|
283
|
+
else
|
284
|
+
{ type: 'object', properties: { route.settings.dig(:swagger, :root) => reference } }
|
285
|
+
end
|
267
286
|
end
|
268
287
|
|
269
288
|
def file_response?(value)
|
data/lib/grape-swagger.rb
CHANGED
@@ -26,7 +26,7 @@ module SwaggerRouting
|
|
26
26
|
def combine_routes(app, doc_klass)
|
27
27
|
app.routes.each do |route|
|
28
28
|
route_path = route.path
|
29
|
-
route_match = route_path.split(/^.*?#{route.prefix
|
29
|
+
route_match = route_path.split(/^.*?#{route.prefix}/).last
|
30
30
|
next unless route_match
|
31
31
|
|
32
32
|
route_match = route_match.match('\/([\w|-]*?)[\.\/\(]') || route_match.match('\/([\w|-]*)$')
|
@@ -0,0 +1,190 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe '751 deeply nested objects' do
|
6
|
+
let(:app) do
|
7
|
+
Class.new(Grape::API) do
|
8
|
+
content_type :json, 'application/json; charset=UTF-8'
|
9
|
+
default_format :json
|
10
|
+
class Vrp < Grape::API
|
11
|
+
def self.vrp_request_timewindow(this)
|
12
|
+
this.optional(:start, types: [String, Float, Integer])
|
13
|
+
this.optional(:end, types: [String, Float, Integer])
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.vrp_request_point(this)
|
17
|
+
this.requires(:id, type: String, allow_blank: false)
|
18
|
+
this.optional(:matrix_index, type: Integer)
|
19
|
+
this.optional(:location, type: Hash) do
|
20
|
+
requires(:lat, type: Float, allow_blank: false)
|
21
|
+
requires(:lon, type: Float, allow_blank: false)
|
22
|
+
end
|
23
|
+
this.at_least_one_of :matrix_index, :location
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.vrp_request_activity(this)
|
27
|
+
this.optional(:duration, types: [String, Float, Integer])
|
28
|
+
this.requires(:point_id, type: String, allow_blank: false)
|
29
|
+
this.optional(:timewindows, type: Array) do
|
30
|
+
Vrp.vrp_request_timewindow(self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.vrp_request_service(this)
|
35
|
+
this.requires(:id, type: String, allow_blank: false)
|
36
|
+
this.optional(:skills, type: Array[String])
|
37
|
+
|
38
|
+
this.optional(:activity, type: Hash) do
|
39
|
+
Vrp.vrp_request_activity(self)
|
40
|
+
end
|
41
|
+
this.optional(:activities, type: Array) do
|
42
|
+
Vrp.vrp_request_activity(self)
|
43
|
+
end
|
44
|
+
this.mutually_exclusive :activity, :activities
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
namespace :vrp do
|
49
|
+
resource :submit do
|
50
|
+
desc 'Submit Problems', nickname: 'vrp'
|
51
|
+
params do
|
52
|
+
optional(:vrp, type: Hash, documentation: { param_type: 'body' }) do
|
53
|
+
optional(:points, type: Array) do
|
54
|
+
Vrp.vrp_request_point(self)
|
55
|
+
end
|
56
|
+
|
57
|
+
optional(:services, type: Array) do
|
58
|
+
Vrp.vrp_request_service(self)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
post do
|
63
|
+
{ vrp: params[:vrp] }.to_json
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
add_swagger_documentation format: :json
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
subject do
|
73
|
+
get '/swagger_doc'
|
74
|
+
JSON.parse(last_response.body)
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'Correctness of vrp Points' do
|
78
|
+
let(:get_points_response) { subject['definitions']['postVrpSubmit']['properties']['vrp']['properties']['points'] }
|
79
|
+
specify do
|
80
|
+
expect(get_points_response).to eql(
|
81
|
+
'type' => 'array',
|
82
|
+
'items' => {
|
83
|
+
'type' => 'object',
|
84
|
+
'properties' => {
|
85
|
+
'id' => {
|
86
|
+
'type' => 'string'
|
87
|
+
},
|
88
|
+
'matrix_index' => {
|
89
|
+
'type' => 'integer',
|
90
|
+
'format' => 'int32'
|
91
|
+
},
|
92
|
+
'location' => {
|
93
|
+
'type' => 'object',
|
94
|
+
'properties' => {
|
95
|
+
'lat' => {
|
96
|
+
'type' => 'number',
|
97
|
+
'format' => 'float'
|
98
|
+
},
|
99
|
+
'lon' => {
|
100
|
+
'type' => 'number',
|
101
|
+
'format' => 'float'
|
102
|
+
}
|
103
|
+
},
|
104
|
+
'required' => %w[lat lon]
|
105
|
+
}
|
106
|
+
},
|
107
|
+
'required' => ['id']
|
108
|
+
}
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe 'Correctness of vrp Services' do
|
114
|
+
let(:get_service_response) { subject['definitions']['postVrpSubmit']['properties']['vrp']['properties']['services'] }
|
115
|
+
specify do
|
116
|
+
expect(get_service_response).to include(
|
117
|
+
'type' => 'array',
|
118
|
+
'items' => {
|
119
|
+
'type' => 'object',
|
120
|
+
'properties' => {
|
121
|
+
'id' => {
|
122
|
+
'type' => 'string'
|
123
|
+
},
|
124
|
+
'skills' => {
|
125
|
+
'type' => 'array',
|
126
|
+
'items' => {
|
127
|
+
'type' => 'string'
|
128
|
+
}
|
129
|
+
},
|
130
|
+
'activity' => {
|
131
|
+
'type' => 'object',
|
132
|
+
'properties' => {
|
133
|
+
'duration' => {
|
134
|
+
'type' => 'string'
|
135
|
+
},
|
136
|
+
'point_id' => {
|
137
|
+
'type' => 'string'
|
138
|
+
},
|
139
|
+
'timewindows' => {
|
140
|
+
'type' => 'array',
|
141
|
+
'items' => {
|
142
|
+
'type' => 'object',
|
143
|
+
'properties' => {
|
144
|
+
'start' => {
|
145
|
+
'type' => 'string'
|
146
|
+
},
|
147
|
+
'end' => {
|
148
|
+
'type' => 'string'
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
},
|
154
|
+
'required' => ['point_id']
|
155
|
+
}, 'activities' => {
|
156
|
+
'type' => 'array',
|
157
|
+
'items' => {
|
158
|
+
'type' => 'object',
|
159
|
+
'properties' => {
|
160
|
+
'duration' => {
|
161
|
+
'type' => 'string'
|
162
|
+
},
|
163
|
+
'point_id' => {
|
164
|
+
'type' => 'string'
|
165
|
+
},
|
166
|
+
'timewindows' => {
|
167
|
+
'type' => 'array',
|
168
|
+
'items' => {
|
169
|
+
'type' => 'object',
|
170
|
+
'properties' => {
|
171
|
+
'start' => {
|
172
|
+
'type' => 'string'
|
173
|
+
},
|
174
|
+
'end' => {
|
175
|
+
'type' => 'string'
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
179
|
+
}
|
180
|
+
},
|
181
|
+
'required' => ['point_id']
|
182
|
+
}
|
183
|
+
}
|
184
|
+
},
|
185
|
+
'required' => ['id']
|
186
|
+
}
|
187
|
+
)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -46,39 +46,63 @@ describe GrapeSwagger::Endpoint::ParamsParser do
|
|
46
46
|
context 'when param is nested in a param of array type' do
|
47
47
|
let(:params) { [['param_1', { type: 'Array' }], ['param_1[param_2]', { type: 'String' }]] }
|
48
48
|
|
49
|
-
it 'skips root parameter' do
|
50
|
-
is_expected.not_to have_key 'param_1'
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'adds is_array option to the nested param' do
|
54
|
-
expect(parse_request_params['param_1[param_2]']).to eq(type: 'String', is_array: true)
|
55
|
-
end
|
56
|
-
|
57
49
|
context 'and array_use_braces setting set to true' do
|
58
50
|
let(:settings) { { array_use_braces: true } }
|
59
51
|
|
60
52
|
it 'adds braces to the param key' do
|
61
|
-
expect(parse_request_params.keys.
|
53
|
+
expect(parse_request_params.keys.last).to eq 'param_1[param_2]'
|
62
54
|
end
|
63
55
|
end
|
64
56
|
end
|
65
57
|
|
66
58
|
context 'when param is nested in a param of hash type' do
|
67
|
-
let(:params) { [
|
68
|
-
|
69
|
-
|
70
|
-
is_expected.not_to have_key 'param_1'
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'does not change options to the nested param' do
|
74
|
-
expect(parse_request_params['param_1[param_2]']).to eq(type: 'String')
|
75
|
-
end
|
59
|
+
let(:params) { [param_1, param_2] }
|
60
|
+
let(:param_1) { ['param_1', { type: 'Hash' }] }
|
61
|
+
let(:param_2) { ['param_1[param_2]', { type: 'String' }] }
|
76
62
|
|
77
63
|
context 'and array_use_braces setting set to true' do
|
78
64
|
let(:settings) { { array_use_braces: true } }
|
79
65
|
|
80
|
-
|
81
|
-
|
66
|
+
context 'and param is of simple type' do
|
67
|
+
it 'does not add braces to the param key' do
|
68
|
+
expect(parse_request_params.keys.last).to eq 'param_1[param_2]'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'and param is of array type' do
|
73
|
+
let(:param_2) { ['param_1[param_2]', { type: 'Array[String]' }] }
|
74
|
+
|
75
|
+
it 'adds braces to the param key' do
|
76
|
+
expect(parse_request_params.keys.last).to eq 'param_1[param_2][]'
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'and `param_type` option is set to body' do
|
80
|
+
let(:param_2) do
|
81
|
+
['param_1[param_2]', { type: 'Array[String]', documentation: { param_type: 'body' } }]
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'does not add braces to the param key' do
|
85
|
+
expect(parse_request_params.keys.last).to eq 'param_1[param_2]'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'and `in` option is set to body' do
|
90
|
+
let(:param_2) do
|
91
|
+
['param_1[param_2]', { type: 'Array[String]', documentation: { in: 'body' } }]
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'does not add braces to the param key' do
|
95
|
+
expect(parse_request_params.keys.last).to eq 'param_1[param_2]'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'and hash `param_type` option is set to body' do
|
100
|
+
let(:param_1) { ['param_1', { type: 'Hash', documentation: { param_type: 'body' } }] }
|
101
|
+
|
102
|
+
it 'does not add braces to the param key' do
|
103
|
+
expect(parse_request_params.keys.last).to eq 'param_1[param_2]'
|
104
|
+
end
|
105
|
+
end
|
82
106
|
end
|
83
107
|
end
|
84
108
|
end
|
data/spec/lib/endpoint_spec.rb
CHANGED
@@ -109,7 +109,7 @@ describe Grape::Endpoint do
|
|
109
109
|
['id', { required: true, type: 'String' }],
|
110
110
|
['description', { required: false, type: 'String' }],
|
111
111
|
['stuffs', { required: true, type: 'Array', is_array: true }],
|
112
|
-
['stuffs[id]', { required: true, type: 'String'
|
112
|
+
['stuffs[id]', { required: true, type: 'String' }]
|
113
113
|
]
|
114
114
|
end
|
115
115
|
|
@@ -138,8 +138,8 @@ describe Grape::Endpoint do
|
|
138
138
|
['stuffs', { required: true, type: 'Array', is_array: true }],
|
139
139
|
['stuffs[owners]', { required: true, type: 'Array', is_array: true }],
|
140
140
|
['stuffs[creators]', { required: true, type: 'Array', is_array: true }],
|
141
|
-
['stuffs[owners][id]', { required: true, type: 'String'
|
142
|
-
['stuffs[creators][id]', { required: true, type: 'String'
|
141
|
+
['stuffs[owners][id]', { required: true, type: 'String' }],
|
142
|
+
['stuffs[creators][id]', { required: true, type: 'String' }],
|
143
143
|
['stuffs_and_things', { required: true, type: 'String' }]
|
144
144
|
]
|
145
145
|
end
|