Skip to content

Commit 08ae87f

Browse files
authored
handle multiple presents (#813)
* handle multiple presents * update documentation and changelog
1 parent 8d245e5 commit 08ae87f

File tree

6 files changed

+165
-7
lines changed

6 files changed

+165
-7
lines changed

.rubocop.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Metrics/BlockLength:
5454
- spec/**/*
5555

5656
Metrics/ClassLength:
57-
Max: 300
57+
Max: 350
5858

5959
Metrics/CyclomaticComplexity:
6060
Max: 17

.rubocop_todo.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Metrics/MethodLength:
2828

2929
# Offense count: 7
3030
Metrics/PerceivedComplexity:
31-
Max: 14
31+
Max: 16
3232

3333
# Offense count: 3
3434
Style/ClassVars:

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#### Features
44

55
* Your contribution here.
6+
* [#813](https://github.com/ruby-grape/grape-swagger/pull/813): Handle multiple presents - [@AntoineGuestin](https://github.com/AntoineGuestin).
67

78
#### Fixes
89

README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ add_swagger_documentation \
458458
* [Response examples documentation](#response-examples)
459459
* [Response headers documentation](#response-headers)
460460
* [Adding root element to responses](#response-root)
461+
* [Multiple present Response](#multiple-response)
461462

462463
#### Swagger Header Parameters <a name="headers"></a>
463464

@@ -1262,6 +1263,75 @@ The result will look like following:
12621263
}
12631264
}
12641265
```
1266+
#### Multiple present Response <a name="multiple-response"></a>
1267+
1268+
You can specify a custom multiple response by using the `as` key:
1269+
```ruby
1270+
desc 'Multiple response',
1271+
success: [
1272+
{ model: Entities::EnumValues, as: :gender },
1273+
{ model: Entities::Something, as: :somethings }
1274+
]
1275+
end
1276+
1277+
get '/things' do
1278+
...
1279+
end
1280+
```
1281+
The result will look like following:
1282+
```
1283+
"responses": {
1284+
"200": {
1285+
"description": "Multiple response",
1286+
"schema":{
1287+
"type":"object",
1288+
"properties":{
1289+
"gender":{
1290+
"$ref":"#/definitions/EnumValues"
1291+
},
1292+
"somethings":{
1293+
"$ref":"#/definitions/Something"
1294+
}
1295+
}
1296+
}
1297+
}
1298+
}
1299+
```
1300+
You can also specify if the response is an array, with the `is_array` key:
1301+
```ruby
1302+
desc 'Multiple response with array',
1303+
success: [
1304+
{ model: Entities::EnumValues, as: :gender },
1305+
{ model: Entities::Something, as: :somethings, is_array: true }
1306+
]
1307+
end
1308+
1309+
get '/things' do
1310+
...
1311+
end
1312+
```
1313+
The result will look like following:
1314+
```
1315+
"responses": {
1316+
"200": {
1317+
"description": "Multiple response with array",
1318+
"schema":{
1319+
"type":"object",
1320+
"properties":{
1321+
"gender":{
1322+
"$ref":"#/definitions/EnumValues"
1323+
},
1324+
"somethings":{
1325+
"type":"array",
1326+
"items":{
1327+
"$ref":"#/definitions/Something"
1328+
}
1329+
}
1330+
}
1331+
}
1332+
}
1333+
}
1334+
```
12651335

12661336
## Using Grape Entities <a name="grape-entity"></a>
12671337

lib/grape-swagger/endpoint.rb

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,7 @@ def params_object(route, options, path)
201201
def response_object(route, options)
202202
codes(route).each_with_object({}) do |value, memo|
203203
value[:message] ||= ''
204-
memo[value[:code]] = { description: value[:message] }
205-
204+
memo[value[:code]] = { description: value[:message] ||= '' } unless memo[value[:code]].present?
206205
memo[value[:code]][:headers] = value[:headers] if value[:headers]
207206

208207
next build_file_response(memo[value[:code]]) if file_response?(value[:model])
@@ -221,7 +220,7 @@ def response_object(route, options)
221220
next if response_model.start_with?('Swagger_doc')
222221

223222
@definitions[response_model][:description] ||= "#{response_model} model"
224-
memo[value[:code]][:schema] = build_reference(route, value, response_model, options)
223+
build_memo_schema(memo, route, value, response_model, options)
225224
memo[value[:code]][:examples] = value[:examples] if value[:examples]
226225
end
227226
end
@@ -268,15 +267,45 @@ def tag_object(route, path)
268267

269268
private
270269

270+
def build_memo_schema(memo, route, value, response_model, options)
271+
if memo[value[:code]][:schema] && value[:as]
272+
memo[value[:code]][:schema][:properties].merge!(build_reference(route, value, response_model, options))
273+
elsif value[:as]
274+
memo[value[:code]][:schema] = {
275+
type: :object,
276+
properties: build_reference(route, value, response_model, options)
277+
}
278+
else
279+
memo[value[:code]][:schema] = build_reference(route, value, response_model, options)
280+
end
281+
end
282+
271283
def build_reference(route, value, response_model, settings)
272284
# TODO: proof that the definition exist, if model isn't specified
273-
reference = { '$ref' => "#/definitions/#{response_model}" }
285+
reference = if value.key?(:as)
286+
{ value[:as] => build_reference_hash(response_model) }
287+
else
288+
build_reference_hash(response_model)
289+
end
274290
return reference unless value[:code] < 300
275291

276-
reference = { type: 'array', items: reference } if route.options[:is_array]
292+
if value.key?(:as) && value.key?(:is_array)
293+
reference[value[:as]] = build_reference_array(reference[value[:as]])
294+
elsif route.options[:is_array]
295+
reference = build_reference_array(reference)
296+
end
297+
277298
build_root(route, reference, response_model, settings)
278299
end
279300

301+
def build_reference_hash(response_model)
302+
{ '$ref' => "#/definitions/#{response_model}" }
303+
end
304+
305+
def build_reference_array(reference)
306+
{ type: 'array', items: reference }
307+
end
308+
280309
def build_root(route, reference, response_model, settings)
281310
default_root = response_model.underscore
282311
default_root = default_root.pluralize if route.options[:is_array]
@@ -382,6 +411,8 @@ def success_code_from_entity(route, entity)
382411
default_code[:message] = entity[:message] || route.description || default_code[:message].sub('{item}', @item)
383412
default_code[:examples] = entity[:examples] if entity[:examples]
384413
default_code[:headers] = entity[:headers] if entity[:headers]
414+
default_code[:as] = entity[:as] if entity[:as]
415+
default_code[:is_array] = entity[:is_array] if entity[:is_array]
385416
else
386417
default_code = GrapeSwagger::DocMethods::StatusCodes.get[route.request_method.downcase.to_sym]
387418
default_code[:model] = entity if entity
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
5+
describe '#776 multiple presents spec' do
6+
include_context "#{MODEL_PARSER} swagger example"
7+
8+
let(:app) do
9+
Class.new(Grape::API) do
10+
namespace :issue_776 do
11+
desc 'Get multiple presents',
12+
success: [
13+
{ model: Entities::EnumValues, as: :gender },
14+
{ model: Entities::Something, as: :somethings, is_array: true }
15+
]
16+
17+
get do
18+
present :gender, { number: 1, gender: 'Male' }, with: Entities::EnumValues
19+
present :somethings, [
20+
{ id: 1, text: 'element_1', links: %w[link1 link2] },
21+
{ id: 2, text: 'element_2', links: %w[link1 link2] }
22+
], with: Entities::Something, is_array: true
23+
end
24+
end
25+
26+
add_swagger_documentation format: :json
27+
end
28+
end
29+
30+
subject do
31+
get '/swagger_doc'
32+
JSON.parse(last_response.body)
33+
end
34+
35+
let(:definitions) { subject['definitions'] }
36+
let(:schema) { subject['paths']['/issue_776']['get']['responses']['200']['schema'] }
37+
38+
specify { expect(definitions.keys).to include 'EnumValues', 'Something' }
39+
40+
specify do
41+
expect(schema).to eql({
42+
'properties' => {
43+
'somethings' => {
44+
'items' => {
45+
'$ref' => '#/definitions/Something'
46+
},
47+
'type' => 'array'
48+
},
49+
'gender' => {
50+
'$ref' => '#/definitions/EnumValues'
51+
}
52+
},
53+
'type' => 'object'
54+
})
55+
end
56+
end

0 commit comments

Comments
 (0)