Skip to content

Commit d27515e

Browse files
committed
Array and object description and inline representers spec
1 parent 2d3a675 commit d27515e

File tree

3 files changed

+176
-10
lines changed

3 files changed

+176
-10
lines changed

lib/grape-swagger/models/representable.rb

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,15 @@ def call
1717

1818
def parse_representer_property(property)
1919
is_a_collection = property.is_a?(::Representable::Hash::Binding::Collection)
20+
documentation = property[:documentation] ? property[:documentation].dup : {}
2021

2122
if property[:decorator] && property[:nested]
22-
representer_mapping(property[:decorator], is_a_collection: is_a_collection, nested: property[:nested])
23+
representer_mapping(property[:decorator], documentation, is_a_collection: is_a_collection, nested: property[:nested])
2324
elsif property[:decorator]
24-
representer_mapping(property[:decorator], is_a_collection: is_a_collection, is_a_decorator: true)
25+
representer_mapping(property[:decorator], documentation, is_a_collection: is_a_collection, is_a_decorator: true)
2526
elsif property[:nested]
26-
representer_mapping(property[:nested], is_a_collection: is_a_collection)
27+
representer_mapping(property[:nested], documentation, is_a_collection: is_a_collection)
2728
else
28-
documentation = property[:documentation] ? property[:documentation].dup : {}
29-
3029
memo = {
3130
description: documentation[:desc] || ''
3231
}
@@ -53,23 +52,42 @@ def parse_representer_property(property)
5352
end
5453
end
5554

56-
def representer_mapping(representer, is_a_collection: false, is_a_decorator: false, nested: nil)
55+
def representer_mapping(representer, documentation, is_a_collection: false, is_a_decorator: false, nested: nil)
5756
if nested.nil? && is_a_decorator
5857
name = endpoint.send(:expose_params_from_model, representer)
5958

6059
if is_a_collection
61-
{ type: :array, items: { '$ref' => "#/definitions/#{name}" } }
60+
{
61+
type: :array,
62+
items: {
63+
'$ref' => "#/definitions/#{name}"
64+
},
65+
description: documentation[:desc] || ''
66+
}
6267
else
63-
{ '$ref' => "#/definitions/#{name}" }
68+
{
69+
'$ref' => "#/definitions/#{name}"
70+
}
6471
end
6572
else
6673
attributes = parse_representer(representer)
6774
attributes = attributes.deep_merge!(parse_representer(nested)) if nested
6875

6976
if is_a_collection
70-
{ type: :array, items: { type: :object, properties: attributes } }
77+
{
78+
type: :array,
79+
items: {
80+
type: :object,
81+
properties: attributes,
82+
description: documentation[:desc] || ''
83+
}
84+
}
7185
else
72-
{ type: :object, properties: attributes }
86+
{
87+
type: :object,
88+
properties: attributes,
89+
description: documentation[:desc] || ''
90+
}
7391
end
7492
end
7593
end
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
require 'spec_helper'
2+
3+
describe 'responseModel' do
4+
before :all do
5+
module ThisInlineApi
6+
module Representers
7+
class Kind < Representable::Decorator
8+
include Representable::JSON
9+
10+
property :id, documentation: { type: Integer, desc: 'Title of the kind.' }
11+
end
12+
13+
class Tag < Representable::Decorator
14+
include Representable::JSON
15+
16+
property :name, documentation: { type: 'string', desc: 'Name' }
17+
end
18+
19+
class Error < Representable::Decorator
20+
include Representable::JSON
21+
22+
property :code, documentation: { type: 'string', desc: 'Error code' }
23+
property :message, documentation: { type: 'string', desc: 'Error message' }
24+
end
25+
26+
class Something < Representable::Decorator
27+
include Representable::JSON
28+
29+
property :text, documentation: { type: 'string', desc: 'Content of something.' }
30+
property :kind, decorator: Kind, documentation: { desc: 'The kind of this something.' }
31+
property :kind2, decorator: Kind, documentation: { desc: 'Secondary kind.' } do
32+
property :name, documentation: { type: String, desc: 'Kind name.' }
33+
end
34+
property :kind3, decorator: ThisInlineApi::Representers::Kind, documentation: { desc: 'Tertiary kind.' }
35+
collection :tags, decorator: ThisInlineApi::Representers::Tag, documentation: { desc: 'Tags.' } do
36+
property :color, documentation: { type: String, desc: 'Tag color.' }
37+
end
38+
end
39+
end
40+
41+
class ResponseModelApi < Grape::API
42+
format :json
43+
desc 'This returns something',
44+
is_array: true,
45+
http_codes: [{ code: 200, message: 'OK', model: Representers::Something }]
46+
get '/something' do
47+
something = OpenStruct.new text: 'something'
48+
Representers::Something.new(something).to_hash
49+
end
50+
51+
# something like an index action
52+
desc 'This returns something or an error',
53+
entity: Representers::Something,
54+
http_codes: [
55+
{ code: 200, message: 'OK', model: Representers::Something },
56+
{ code: 403, message: 'Refused to return something', model: Representers::Error }
57+
]
58+
params do
59+
optional :id, type: Integer
60+
end
61+
get '/something/:id' do
62+
if params[:id] == 1
63+
something = OpenStruct.new text: 'something'
64+
Representers::Something.new(something).to_hash
65+
else
66+
error = OpenStruct.new code: 'some_error', message: 'Some error'
67+
Representers::Error.new(error).to_hash
68+
end
69+
end
70+
71+
add_swagger_documentation
72+
end
73+
end
74+
end
75+
76+
def app
77+
ThisInlineApi::ResponseModelApi
78+
end
79+
80+
subject do
81+
get '/swagger_doc/something'
82+
JSON.parse(last_response.body)
83+
end
84+
85+
it 'documents index action' do
86+
expect(subject['paths']['/something']['get']['responses']).to eq(
87+
'200' => {
88+
'description' => 'OK',
89+
'schema' => {
90+
'type' => 'array',
91+
'items' => { '$ref' => '#/definitions/Something' } }
92+
}
93+
)
94+
end
95+
96+
it 'should document specified models as show action' do
97+
expect(subject['paths']['/something/{id}']['get']['responses']).to eq(
98+
'200' => {
99+
'description' => 'OK',
100+
'schema' => { '$ref' => '#/definitions/Something' }
101+
},
102+
'403' => {
103+
'description' => 'Refused to return something',
104+
'schema' => { '$ref' => '#/definitions/Error' }
105+
}
106+
)
107+
expect(subject['definitions'].keys).to include 'Error'
108+
expect(subject['definitions']['Error']).to eq(
109+
'type' => 'object',
110+
'description' => 'This returns something or an error',
111+
'properties' => {
112+
'code' => { 'type' => 'string', 'description' => 'Error code' },
113+
'message' => { 'type' => 'string', 'description' => 'Error message' }
114+
}
115+
)
116+
117+
expect(subject['definitions'].keys).to include 'Something'
118+
expect(subject['definitions']['Something']).to eq(
119+
'type' => 'object',
120+
'description' => 'This returns something or an error',
121+
'properties' => {
122+
'text' => { 'description' => 'Content of something.', 'type' => 'string' },
123+
'kind' => { '$ref' => '#/definitions/Kind' },
124+
'kind2' => {
125+
'type' => 'object',
126+
'properties' => {
127+
'id' => { 'description' => 'Title of the kind.', 'type' => 'integer', 'format' => 'int32' },
128+
'name' => { 'description' => 'Kind name.', 'type' => 'string' } },
129+
'description' => 'Secondary kind.' },
130+
'kind3' => { '$ref' => '#/definitions/Kind' },
131+
'tags' => {
132+
'type' => 'array',
133+
'items' => {
134+
'type' => 'object',
135+
'properties' => {
136+
'name' => { 'description' => 'Name', 'type' => 'string' },
137+
'color' => { 'description' => 'Tag color.', 'type' => 'string' } },
138+
'description' => 'Tags.' }
139+
}
140+
}
141+
)
142+
143+
expect(subject['definitions'].keys).to include 'Kind'
144+
expect(subject['definitions']['Kind']).to eq(
145+
'type' => 'object', 'properties' => { 'id' => { 'description' => 'Title of the kind.', 'type' => 'integer', 'format' => 'int32' } }
146+
)
147+
end
148+
end

0 commit comments

Comments
 (0)