Skip to content

Commit e99f798

Browse files
author
peter scholz
committed
Merge pull request #363 from LeFnord/master
some more parameter corrections
2 parents 0a341bb + 18401c8 commit e99f798

8 files changed

+115
-57
lines changed

.rubocop_todo.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Metrics/AbcSize:
1313
# Offense count: 1
1414
# Configuration parameters: CountComments.
1515
Metrics/ClassLength:
16-
Max: 230
16+
Max: 233
1717

1818
# Offense count: 6
1919
Metrics/CyclomaticComplexity:

lib/grape-swagger.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
require 'grape-swagger/endpoint'
44
require 'grape-swagger/errors'
55

6-
# TODO: loading should be simplified by using a better/more clever dependincy structure
76
require 'grape-swagger/doc_methods/produces_consumes'
87
require 'grape-swagger/doc_methods/data_type'
98
require 'grape-swagger/doc_methods/extensions'
@@ -12,6 +11,7 @@
1211
require 'grape-swagger/doc_methods/path_string'
1312
require 'grape-swagger/doc_methods/tag_name_description'
1413
require 'grape-swagger/doc_methods/parse_params'
14+
# require 'grape-swagger/doc_methods/move_params'
1515

1616
require 'grape-swagger/doc_methods'
1717

lib/grape-swagger/doc_methods/data_type.rb

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ class DataType
44
class << self
55
def call(value)
66
raw_data_type = value[:type] if value.is_a?(Hash)
7+
raw_data_type = value unless value.is_a?(Hash)
78
raw_data_type ||= 'string'
89
case raw_data_type.to_s
910
when 'Boolean', 'Date', 'Integer', 'String', 'Float', 'JSON', 'Array'

lib/grape-swagger/endpoint.rb

+48-40
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,6 @@ def path_item(routes, options)
8989
@item, path = GrapeSwagger::DocMethods::PathString.build(route.route_path, options)
9090
@entity = route.route_entity || route.route_success
9191

92-
# ... replacing version params through submitted version
93-
9492
method = route.route_method.downcase.to_sym
9593
request_params = method_object(route, options, path)
9694

@@ -124,14 +122,6 @@ def description_object(route, markdown)
124122
description
125123
end
126124

127-
def consumes_object(route, format)
128-
method = route.route_method.downcase.to_sym
129-
format = route.route_settings[:description][:consumes] if route.route_settings[:description] && route.route_settings[:description][:consumes]
130-
mime_types = GrapeSwagger::DocMethods::ProducesConsumes.call(format) if [:post, :put].include?(method)
131-
132-
mime_types
133-
end
134-
135125
def produces_object(route, format)
136126
mime_types = GrapeSwagger::DocMethods::ProducesConsumes.call(format)
137127

@@ -143,13 +133,27 @@ def produces_object(route, format)
143133
route_mime_types.present? ? route_mime_types : mime_types
144134
end
145135

136+
def consumes_object(route, format)
137+
method = route.route_method.downcase.to_sym
138+
format = route.route_settings[:description][:consumes] if route.route_settings[:description] && route.route_settings[:description][:consumes]
139+
mime_types = GrapeSwagger::DocMethods::ProducesConsumes.call(format) if [:post, :put].include?(method)
140+
141+
mime_types
142+
end
143+
144+
def params_object(route)
145+
partition_params(route).map do |param, value|
146+
value = { required: false }.merge(value) if value.is_a?(Hash)
147+
GrapeSwagger::DocMethods::ParseParams.call(param, value, route)
148+
end
149+
end
150+
146151
def response_object(route)
147-
default_code = default_staus_codes[route.route_method.downcase.to_sym]
152+
default_code = default_status_codes[route.route_method.downcase.to_sym]
148153
default_code[:model] = @entity if @entity
149154
default_code[:message] = route.route_description || default_code[:message].sub('{item}', @item)
150155

151156
codes = [default_code] + (route.route_http_codes || route.route_failure || [])
152-
153157
codes.map! { |x| x.is_a?(Array) ? { code: x[0], message: x[1], model: x[2] } : x }
154158

155159
codes.each_with_object({}) do |value, memo|
@@ -158,6 +162,8 @@ def response_object(route)
158162
response_model = @item
159163
response_model = expose_params_from_model(value[:model]) if value[:model]
160164

165+
memo[204] = memo.delete(200) if memo.key?(200) && route.route_method == 'DELETE' && value[:model].nil?
166+
161167
next unless !response_model.start_with?('Swagger_doc') &&
162168
((@definitions[response_model] && value[:code].to_s.start_with?('2')) || value[:model])
163169

@@ -170,40 +176,32 @@ def response_object(route)
170176
end
171177
end
172178

173-
def default_staus_codes
174-
{
175-
get: { code: 200, message: 'get {item}(s)' },
176-
post: { code: 201, message: 'created {item}' },
177-
put: { code: 200, message: 'updated {item}' },
178-
patch: { code: 200, message: 'patched {item}' },
179-
delete: { code: 200, message: 'deleted {item}' }
180-
}
179+
def tag_object(route, version)
180+
Array(route.route_path.split('{')[0].split('/').reject(&:empty?).delete_if { |i| ((i == route.route_prefix.to_s) || (i == version)) }.first)
181181
end
182182

183-
def params_object(route)
184-
partition_params(route).map do |param, value|
185-
value = { required: false }.merge(value) if value.is_a?(Hash)
186-
GrapeSwagger::DocMethods::ParseParams.call(param, value, route)
187-
end
188-
end
183+
private
189184

190185
def partition_params(route)
191186
declared_params = route.route_settings[:declared_params] if route.route_settings[:declared_params].present?
192187
required, exposed = route.route_params.partition { |x| x.first.is_a? String }
193188

194189
unless declared_params.nil?
195-
required_params = parse_request_params(required)
190+
request_params = parse_request_params(required)
196191
end
197192

198-
if !exposed.empty? && !@entity
193+
if !exposed.empty?
199194
exposed_params = exposed.each_with_object({}) { |x, memo| memo[x.first] = x.last }
200195
properties = parse_response_params(exposed_params)
201-
202-
@definitions[@item] = { properties: properties }
196+
else
197+
properties = parse_response_params(required)
203198
end
204199

200+
key = model_name(@entity || @item)
201+
@definitions[key] = { type: 'object', properties: properties } unless properties.empty? || @definitions.key?(key) || (route.route_method == 'DELETE' && !@entity)
202+
205203
return route.route_params if route.route_params && !route.route_settings[:declared_params].present?
206-
required_params || {}
204+
request_params || {}
207205
end
208206

209207
def parse_request_params(required)
@@ -237,11 +235,12 @@ def parse_response_params(params)
237235
{ '$ref' => "#/definitions/#{name}" }
238236
end
239237
else
240-
241-
data_type = GrapeSwagger::DocMethods::DataType.call(x.last[:documentation] || x.last)
238+
documented_type = x.last[:type]
239+
documented_type ||= x.last[:documentation][:type] if x.last[:documentation]
240+
data_type = GrapeSwagger::DocMethods::DataType.call(documented_type)
242241

243242
if GrapeSwagger::DocMethods::DataType.primitive?(data_type)
244-
data = GrapeSwagger::DocMethods::DataType::PRIMITIVE_MAPPINGS[data_type]
243+
data = GrapeSwagger::DocMethods::DataType.mapping(data_type)
245244
memo[x.first] = { type: data.first, format: data.last }
246245
else
247246
memo[x.first] = { type: data_type }
@@ -253,9 +252,8 @@ def parse_response_params(params)
253252
end
254253

255254
def expose_params_from_model(model)
256-
model_name = model.respond_to?(:name) ? model.name.demodulize.camelize : model.split('::').last
255+
model_name = model_name(model)
257256

258-
# DONE: has to be adept, to be ready for grape-entity >0.5.0
259257
# TODO: this should only be a temporary hack ;)
260258
if GrapeEntity::VERSION =~ /0\.4\.\d/
261259
parameters = model.exposures ? model.exposures : model.documentation
@@ -271,6 +269,20 @@ def expose_params_from_model(model)
271269
model_name
272270
end
273271

272+
def model_name(name)
273+
name.respond_to?(:name) ? name.name.demodulize.camelize : name.split('::').last
274+
end
275+
276+
def default_status_codes
277+
{
278+
get: { code: 200, message: 'get {item}(s)' },
279+
post: { code: 201, message: 'created {item}' },
280+
put: { code: 200, message: 'updated {item}' },
281+
patch: { code: 200, message: 'patched {item}' },
282+
delete: { code: 200, message: 'deleted {item}' }
283+
}
284+
end
285+
274286
def could_it_be_a_model?(value)
275287
(
276288
value[:type].to_s.include?('Entity') || value[:type].to_s.include?('Entities')
@@ -289,9 +301,5 @@ def hidden?(route)
289301

290302
false
291303
end
292-
293-
def tag_object(route, version)
294-
Array(route.route_path.split('{')[0].split('/').reject(&:empty?).delete_if { |i| ((i == route.route_prefix.to_s) || (i == version)) }.first)
295-
end
296304
end
297305
end

spec/support/api_swagger_v2_result.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,14 @@ class ApiError < Grape::Entity
151151
"delete"=>{
152152
"produces"=>["application/json"],
153153
"parameters"=>[{"in"=>"path", "name"=>"id", "description"=>nil, "required"=>true, "type"=>"integer", "format"=>"int32"}],
154-
"responses"=>{"200"=>{"description"=>"dummy route."}, "401"=>{"description"=>"Unauthorized"}},
154+
"responses"=>{"204"=>{"description"=>"dummy route."}, "401"=>{"description"=>"Unauthorized"}},
155155
"tags"=>["dummy"],
156156
"operationId"=>"deleteDummyId"
157157
}}},
158158
"definitions"=>{
159-
"QueryInputElement"=>{"type"=>"object", "properties"=>{"key"=>{"type"=>"string"}, "value"=>{"type"=>"string"}}},
160159
"QueryInput"=>{"type"=>"object", "properties"=>{"elements"=>{"type"=>"array", "items"=>{"$ref"=>"#/definitions/QueryInputElement"}}}},
161-
"Thing"=>{"properties"=>{"id"=>{"type"=>"integer", "format"=>"int32"}, "text"=>{"type"=>"string"}, "links"=>{"type"=>"link"}, "others"=>{"type"=>"text"}}},
160+
"QueryInputElement"=>{"type"=>"object", "properties"=>{"key"=>{"type"=>"string"}, "value"=>{"type"=>"string"}}},
161+
"Thing"=>{"type"=>"object", "properties"=>{"id"=>{"type"=>"integer", "format"=>"int32"}, "text"=>{"type"=>"string"}, "links"=>{"type"=>"link"}, "others"=>{"type"=>"text"}}},
162162
"ApiError"=>{"type"=>"object", "properties"=>{"code"=>{"type"=>"integer", "format"=>"int32"}, "message"=>{"type"=>"string"}}},
163163
"Something"=>{"type"=>"object", "properties"=>{"id"=>{"type"=>"integer", "format"=>"int32"}, "text"=>{"type"=>"string"}, "links"=>{"type"=>"link"}, "others"=>{"type"=>"text"}}}
164164
}}

spec/swagger_v2/api_swagger_v2_param_type_spec.rb

+54-6
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class ParamTypeApi < Grape::API
5050
optional :in_header, type: String, documentation: { in: 'header' }
5151
end
5252

53-
get '/defined_param_type' do
53+
get '/defined_in' do
5454
{ "declared_params" => declared(params) }
5555
end
5656

@@ -62,19 +62,18 @@ class ParamTypeApi < Grape::API
6262
optional :in_header, type: String, documentation: { in: 'header' }
6363
end
6464

65-
get '/defined_param_type/:in_path' do
65+
get '/defined_in/:in_path' do
6666
{ "declared_params" => declared(params) }
6767
end
6868

69-
desc 'full set of request param types using `:in`',
70-
success: TheApi::Entities::UseResponse
69+
desc 'full set of request param types using `:in`'
7170
params do
7271
optional :in_path, type: Integer
7372
optional :in_query, type: String, documentation: { in: 'query' }
7473
optional :in_header, type: String, documentation: { in: 'header' }
7574
end
7675

77-
delete '/defined_param_type/:in_path' do
76+
delete '/defined_in/:in_path' do
7877
{ "declared_params" => declared(params) }
7978
end
8079

@@ -109,6 +108,25 @@ def app
109108
TheApi::ParamTypeApi
110109
end
111110

111+
describe 'foo' do
112+
subject do
113+
get '/swagger_doc'
114+
JSON.parse(last_response.body)
115+
end
116+
117+
specify do
118+
expect(subject['paths']['/defined_param_type/{in_path}']['delete']['responses']).to eql({
119+
"200"=>{"description"=>"full set of request param types", "schema"=>{"$ref"=>"#/definitions/UseResponse"}}
120+
})
121+
end
122+
123+
specify do
124+
expect(subject['paths']['/defined_in/{in_path}']['delete']['responses']).to eql({
125+
"204"=>{"description"=>"full set of request param types using `:in`"}
126+
})
127+
end
128+
end
129+
112130
describe 'defined param types' do
113131
subject do
114132
get '/swagger_doc/defined_param_type'
@@ -139,7 +157,37 @@ def app
139157
end
140158
end
141159

142-
describe 'file up-, download' do
160+
describe 'defined param types with `:in`' do
161+
subject do
162+
get '/swagger_doc/defined_in'
163+
JSON.parse(last_response.body)
164+
end
165+
166+
specify do
167+
expect(subject['paths']['/defined_in']['get']['parameters']).to eql([
168+
{"in"=>"query", "name"=>"in_query", "description"=>nil, "required"=>false, "type"=>"string"},
169+
{"in"=>"header", "name"=>"in_header", "description"=>nil, "required"=>false, "type"=>"string"},
170+
])
171+
end
172+
173+
specify do
174+
expect(subject['paths']['/defined_in/{in_path}']['get']['parameters']).to eql([
175+
{"in"=>"path", "name"=>"in_path", "description"=>nil, "required"=>true, "type"=>"integer", "format"=>"int32"},
176+
{"in"=>"query", "name"=>"in_query", "description"=>nil, "required"=>false, "type"=>"string"},
177+
{"in"=>"header", "name"=>"in_header", "description"=>nil, "required"=>false, "type"=>"string"},
178+
])
179+
end
180+
181+
specify do
182+
expect(subject['paths']['/defined_in/{in_path}']['delete']['parameters']).to eql([
183+
{"in"=>"path", "name"=>"in_path", "description"=>nil, "required"=>true, "type"=>"integer", "format"=>"int32"},
184+
{"in"=>"query", "name"=>"in_query", "description"=>nil, "required"=>false, "type"=>"string"},
185+
{"in"=>"header", "name"=>"in_header", "description"=>nil, "required"=>false, "type"=>"string"},
186+
])
187+
end
188+
end
189+
190+
describe 'file' do
143191
describe 'upload' do
144192
subject do
145193
get '/swagger_doc/upload'

spec/swagger_v2/api_swagger_v2_response_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def app
149149
"400"=>{"description"=>"NotFound", "schema"=>{"$ref"=>"#/definitions/ApiError"}}}
150150
}}},
151151
"definitions"=>{
152-
"ParamsResponse"=>{"properties"=>{"description"=>{"type"=>"string"}, "$responses"=>{"type"=>"string"}}},
152+
"ParamsResponse"=>{"type"=>"object", "properties"=>{"description"=>{"type"=>"string"}, "$responses"=>{"type"=>"string"}}},
153153
"ApiError"=>{"type"=>"object", "properties"=>{"code"=>{"type"=>"integer", "format"=>"int32"}, "message"=>{"type"=>"string"}}}
154154
}})
155155
end

spec/swagger_v2/simple_mounted_api_spec.rb

+6-5
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,17 @@ def app
113113
"parameters"=>[{"in"=>"formData", "name"=>"items[]", "description"=>"array of items", "required"=>false, "type"=>"array", "items"=>{"type"=>"string"}}],
114114
"tags"=>["items"],
115115
"operationId"=>"postItems",
116-
"responses"=>{"201"=>{"description"=>"this takes an array of parameters"}}
116+
"responses"=>{"201"=>{"description"=>"this takes an array of parameters", "schema"=>{"$ref"=>"#/definitions/Item"}}}
117117
}},
118118
"/custom"=>{
119119
"get"=>{
120120
"produces"=>["application/json"],
121121
"parameters"=>[{"in"=>"formData", "name"=>"custom", "description"=>"array of items", "required"=>false, "type"=>"array", "items"=>{"type"=>"CustomType"}}],
122122
"tags"=>["custom"],
123123
"operationId"=>"getCustom",
124-
"responses"=>{"200"=>{"description"=>"this uses a custom parameter"}}}
125-
}}})
124+
"responses"=>{"200"=>{"description"=>"this uses a custom parameter", "schema"=>{"$ref"=>"#/definitions/Custom"}}}}
125+
}},
126+
"definitions"=>{"Item"=>{"type"=>"object", "properties"=>{"items[]"=>{"type"=>"string"}}}, "Custom"=>{"type"=>"object", "properties"=>{"custom"=>{"type"=>"CustomType"}}}}})
126127
end
127128
end
128129

@@ -216,7 +217,7 @@ def app
216217
"parameters"=>[{"in"=>"formData", "name"=>"items[]", "description"=>"array of items", "required"=>false, "type"=>"array", "items"=>{"type"=>"string"}}],
217218
"tags"=>["items"],
218219
"operationId"=>"postItems",
219-
"responses"=>{"201"=>{"description"=>"this takes an array of parameters"}}}
220+
"responses"=>{"201"=>{"description"=>"this takes an array of parameters", "schema"=>{"$ref"=>"#/definitions/Item"}}}}
220221
}})
221222
end
222223
end
@@ -235,7 +236,7 @@ def app
235236
"parameters"=>[{"in"=>"formData", "name"=>"custom", "description"=>"array of items", "required"=>false, "type"=>"array", "items"=>{"type"=>"CustomType"}}],
236237
"tags"=>["custom"],
237238
"operationId"=>"getCustom",
238-
"responses"=>{"200"=>{"description"=>"this uses a custom parameter"}}}
239+
"responses"=>{"200"=>{"description"=>"this uses a custom parameter", "schema"=>{"$ref"=>"#/definitions/Custom"}}}}
239240
}})
240241
end
241242
end

0 commit comments

Comments
 (0)