grape-swagger 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -33
- data/.rubocop_todo.yml +55 -0
- data/.travis.yml +12 -4
- data/CHANGELOG.md +14 -0
- data/Gemfile +8 -1
- data/README.md +10 -8
- data/{test → example}/api.rb +4 -0
- data/{test → example}/config.ru +0 -0
- data/{test → example}/splines.png +0 -0
- data/grape-swagger.gemspec +2 -2
- data/lib/grape-swagger.rb +211 -193
- data/lib/grape-swagger/version.rb +1 -1
- data/spec/api_global_models_spec.rb +10 -7
- data/spec/api_models_spec.rb +45 -17
- data/spec/api_paths_spec.rb +67 -0
- data/spec/api_root_spec.rb +31 -0
- data/spec/boolean_params_spec.rb +30 -0
- data/spec/form_params_spec.rb +7 -43
- data/spec/grape-swagger_helper_spec.rb +1 -23
- data/spec/group_params_spec.rb +31 -0
- data/spec/hash_params_spec.rb +30 -0
- data/spec/hide_api_spec.rb +3 -3
- data/spec/non_default_api_spec.rb +25 -22
- data/spec/response_model_spec.rb +42 -11
- data/spec/simple_mounted_api_spec.rb +3 -3
- data/spec/spec_helper.rb +1 -0
- metadata +20 -12
@@ -7,10 +7,12 @@ describe 'Global Models' do
|
|
7
7
|
module Some
|
8
8
|
class Thing < Grape::Entity
|
9
9
|
expose :text, documentation: { type: 'string', desc: 'Content of something.' }
|
10
|
+
expose :name, documentation: { type: String, desc: 'Name of something.' }
|
10
11
|
end
|
11
12
|
|
12
13
|
class CombinedThing < Grape::Entity
|
13
14
|
expose :text, documentation: { type: 'string', desc: 'Content of something.' }
|
15
|
+
expose :created_at, documentation: { type: DateTime, desc: 'Creation of something.' }
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
@@ -18,15 +20,13 @@ describe 'Global Models' do
|
|
18
20
|
|
19
21
|
subject do
|
20
22
|
Class.new(Grape::API) do
|
21
|
-
desc 'This gets thing.'
|
23
|
+
desc 'This gets thing.'
|
22
24
|
get '/thing' do
|
23
25
|
thing = OpenStruct.new text: 'thing'
|
24
26
|
present thing, with: Entities::Some::Thing
|
25
27
|
end
|
26
28
|
|
27
|
-
desc 'This gets combined thing.',
|
28
|
-
params: Entities::Some::CombinedThing.documentation,
|
29
|
-
entity: Entities::Some::CombinedThing
|
29
|
+
desc 'This gets combined thing.', entity: Entities::Some::CombinedThing
|
30
30
|
get '/combined_thing' do
|
31
31
|
thing = OpenStruct.new text: 'thing'
|
32
32
|
present thing, with: Entities::Some::CombinedThing
|
@@ -47,7 +47,8 @@ describe 'Global Models' do
|
|
47
47
|
'Some::Thing' => {
|
48
48
|
'id' => 'Some::Thing',
|
49
49
|
'properties' => {
|
50
|
-
'text' => { 'type' => 'string', 'description' => 'Content of something.' }
|
50
|
+
'text' => { 'type' => 'string', 'description' => 'Content of something.' },
|
51
|
+
'name' => { 'type' => 'string', 'description' => 'Name of something.' }
|
51
52
|
}
|
52
53
|
})
|
53
54
|
end
|
@@ -60,7 +61,8 @@ describe 'Global Models' do
|
|
60
61
|
'Some::Thing' => {
|
61
62
|
'id' => 'Some::Thing',
|
62
63
|
'properties' => {
|
63
|
-
'text' => { 'type' => 'string', 'description' => 'Content of something.' }
|
64
|
+
'text' => { 'type' => 'string', 'description' => 'Content of something.' },
|
65
|
+
'name' => { 'type' => 'string', 'description' => 'Name of something.' }
|
64
66
|
}
|
65
67
|
})
|
66
68
|
|
@@ -68,7 +70,8 @@ describe 'Global Models' do
|
|
68
70
|
'Some::CombinedThing' => {
|
69
71
|
'id' => 'Some::CombinedThing',
|
70
72
|
'properties' => {
|
71
|
-
'text' => { 'type' => 'string', 'description' => 'Content of something.' }
|
73
|
+
'text' => { 'type' => 'string', 'description' => 'Content of something.' },
|
74
|
+
'created_at' => { 'type' => 'dateTime', 'description' => 'Creation of something.' }
|
72
75
|
}
|
73
76
|
})
|
74
77
|
|
data/spec/api_models_spec.rb
CHANGED
@@ -6,6 +6,7 @@ describe 'API Models' do
|
|
6
6
|
module Entities
|
7
7
|
class Something < Grape::Entity
|
8
8
|
expose :text, documentation: { type: 'string', desc: 'Content of something.' }
|
9
|
+
expose :links, documentation: { type: 'link', is_array: true }
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
@@ -51,6 +52,24 @@ describe 'API Models' do
|
|
51
52
|
expose :something, as: :post, using: Entities::Something, documentation: { type: 'Something', desc: 'Reference to something.' }
|
52
53
|
end
|
53
54
|
end
|
55
|
+
|
56
|
+
module Entities
|
57
|
+
class FourthLevel < Grape::Entity
|
58
|
+
expose :text, documentation: { type: 'string' }
|
59
|
+
end
|
60
|
+
|
61
|
+
class ThirdLevel < Grape::Entity
|
62
|
+
expose :parts, using: Entities::FourthLevel, documentation: { type: 'FourthLevel' }
|
63
|
+
end
|
64
|
+
|
65
|
+
class SecondLevel < Grape::Entity
|
66
|
+
expose :parts, using: Entities::ThirdLevel, documentation: { type: 'ThirdLevel' }
|
67
|
+
end
|
68
|
+
|
69
|
+
class FirstLevel < Grape::Entity
|
70
|
+
expose :parts, using: Entities::SecondLevel, documentation: { type: 'SecondLevel' }
|
71
|
+
end
|
72
|
+
end
|
54
73
|
end
|
55
74
|
|
56
75
|
def app
|
@@ -91,6 +110,16 @@ describe 'API Models' do
|
|
91
110
|
present something, with: Entities::AliasedThing
|
92
111
|
end
|
93
112
|
|
113
|
+
desc 'This gets all nested entities.', entity: Entities::FirstLevel
|
114
|
+
get '/nesting' do
|
115
|
+
fourth_level = OpenStruct.new text: 'something'
|
116
|
+
third_level = OpenStruct.new parts: [fourth_level]
|
117
|
+
second_level = OpenStruct.new parts: [third_level]
|
118
|
+
first_level = OpenStruct.new parts: [second_level]
|
119
|
+
|
120
|
+
present first_level, with: Entities::FirstLevel
|
121
|
+
end
|
122
|
+
|
94
123
|
add_swagger_documentation
|
95
124
|
end
|
96
125
|
end
|
@@ -117,37 +146,28 @@ describe 'API Models' do
|
|
117
146
|
{ 'path' => '/somethingelse.{format}', 'description' => 'Operations about somethingelses' },
|
118
147
|
{ 'path' => '/enum_description_in_entity.{format}', 'description' => 'Operations about enum_description_in_entities' },
|
119
148
|
{ 'path' => '/aliasedthing.{format}', 'description' => 'Operations about aliasedthings' },
|
149
|
+
{ 'path' => '/nesting.{format}', 'description' => 'Operations about nestings' },
|
120
150
|
{ 'path' => '/swagger_doc.{format}', 'description' => 'Operations about swagger_docs' }
|
121
151
|
]
|
122
152
|
end
|
123
153
|
end
|
124
154
|
|
125
155
|
it 'returns type' do
|
126
|
-
get '/swagger_doc/something
|
156
|
+
get '/swagger_doc/something'
|
127
157
|
result = JSON.parse(last_response.body)
|
128
158
|
expect(result['apis'].first['operations'].first['type']).to eq 'Something'
|
129
159
|
end
|
130
160
|
|
131
161
|
it 'includes nested type' do
|
132
|
-
get '/swagger_doc/thing
|
162
|
+
get '/swagger_doc/thing'
|
133
163
|
result = JSON.parse(last_response.body)
|
134
164
|
expect(result['apis'].first['operations'].first['type']).to eq 'Some::Thing'
|
135
165
|
end
|
136
166
|
|
137
167
|
it 'includes entities which are only used as composition' do
|
138
|
-
get '/swagger_doc/somethingelse
|
168
|
+
get '/swagger_doc/somethingelse'
|
139
169
|
result = JSON.parse(last_response.body)
|
140
|
-
expect(result['apis']).to
|
141
|
-
'path' => '/somethingelse.{format}',
|
142
|
-
'operations' => [{
|
143
|
-
'notes' => '',
|
144
|
-
'type' => 'SomeThingElse',
|
145
|
-
'summary' => 'This gets somthing else.',
|
146
|
-
'nickname' => 'GET-somethingelse---format-',
|
147
|
-
'method' => 'GET',
|
148
|
-
'parameters' => []
|
149
|
-
}]
|
150
|
-
}])
|
170
|
+
expect(result['apis'][0]['path']).to start_with '/somethingelse'
|
151
171
|
|
152
172
|
expect(result['models']['SomeThingElse']).to include('id' => 'SomeThingElse',
|
153
173
|
'properties' => {
|
@@ -188,7 +208,7 @@ describe 'API Models' do
|
|
188
208
|
end
|
189
209
|
|
190
210
|
it 'includes enum values in params and documentation.' do
|
191
|
-
get '/swagger_doc/enum_description_in_entity
|
211
|
+
get '/swagger_doc/enum_description_in_entity'
|
192
212
|
result = JSON.parse(last_response.body)
|
193
213
|
expect(result['models']['EnumValues']).to eq(
|
194
214
|
'id' => 'EnumValues',
|
@@ -210,7 +230,7 @@ describe 'API Models' do
|
|
210
230
|
end
|
211
231
|
|
212
232
|
it 'includes referenced models in those with aliased references.' do
|
213
|
-
get '/swagger_doc/aliasedthing
|
233
|
+
get '/swagger_doc/aliasedthing'
|
214
234
|
result = JSON.parse(last_response.body)
|
215
235
|
expect(result['models']['AliasedThing']).to eq(
|
216
236
|
'id' => 'AliasedThing',
|
@@ -222,8 +242,16 @@ describe 'API Models' do
|
|
222
242
|
expect(result['models']['Something']).to eq(
|
223
243
|
'id' => 'Something',
|
224
244
|
'properties' => {
|
225
|
-
'text' => { 'type' => 'string', 'description' => 'Content of something.' }
|
245
|
+
'text' => { 'type' => 'string', 'description' => 'Content of something.' },
|
246
|
+
'links' => { 'type' => 'array', 'items' => { '$ref' => 'link' } }
|
226
247
|
}
|
227
248
|
)
|
228
249
|
end
|
250
|
+
|
251
|
+
it 'includes all entities with four levels of nesting' do
|
252
|
+
get '/swagger_doc/nesting'
|
253
|
+
result = JSON.parse(last_response.body)
|
254
|
+
|
255
|
+
expect(result['models']).to include('FirstLevel', 'SecondLevel', 'ThirdLevel', 'FourthLevel')
|
256
|
+
end
|
229
257
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'simple api with prefix' do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
class ApiWithPrefix < Grape::API
|
7
|
+
prefix :api
|
8
|
+
|
9
|
+
desc 'This gets apitest'
|
10
|
+
get '/apitest' do
|
11
|
+
{ test: 'something' }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class SimpleApiWithPrefix < Grape::API
|
16
|
+
mount ApiWithPrefix
|
17
|
+
add_swagger_documentation
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
def app
|
23
|
+
SimpleApiWithPrefix
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should not raise TypeError exception' do
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'retrieves swagger-documentation on /swagger_doc that contains apitest' do
|
30
|
+
get '/swagger_doc.json'
|
31
|
+
expect(JSON.parse(last_response.body)).to eq(
|
32
|
+
'apiVersion' => '0.1',
|
33
|
+
'swaggerVersion' => '1.2',
|
34
|
+
'info' => {},
|
35
|
+
'produces' => Grape::ContentTypes::CONTENT_TYPES.values.uniq,
|
36
|
+
'apis' => [
|
37
|
+
{ 'path' => '/apitest.{format}', 'description' => 'Operations about apitests' },
|
38
|
+
{ 'path' => '/swagger_doc.{format}', 'description' => 'Operations about swagger_docs' }
|
39
|
+
]
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'retrieves the documentation for apitest that' do
|
44
|
+
it 'contains returns something in URL' do
|
45
|
+
get '/swagger_doc/apitest.json'
|
46
|
+
expect(JSON.parse(last_response.body)).to eq(
|
47
|
+
'apiVersion' => '0.1',
|
48
|
+
'swaggerVersion' => '1.2',
|
49
|
+
'basePath' => 'http://example.org',
|
50
|
+
'resourcePath' => '/apitest',
|
51
|
+
'produces' => Grape::ContentTypes::CONTENT_TYPES.values.uniq,
|
52
|
+
'apis' => [{
|
53
|
+
'path' => '/api/apitest.{format}',
|
54
|
+
'operations' => [{
|
55
|
+
'notes' => '',
|
56
|
+
'summary' => 'This gets apitest',
|
57
|
+
'nickname' => 'GET-api-apitest---format-',
|
58
|
+
'method' => 'GET',
|
59
|
+
'parameters' => [],
|
60
|
+
'type' => 'void'
|
61
|
+
}]
|
62
|
+
}]
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'simple root api' do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
class ApiRoot < Grape::API
|
7
|
+
format :json
|
8
|
+
prefix 'api'
|
9
|
+
version 'v2', using: :header, vendor: 'artsy', strict: false
|
10
|
+
get do
|
11
|
+
{}
|
12
|
+
end
|
13
|
+
add_swagger_documentation
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def app
|
18
|
+
ApiRoot
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'retrieves swagger-documentation on /swagger_doc' do
|
22
|
+
get '/api/swagger_doc'
|
23
|
+
expect(JSON.parse(last_response.body)).to eq(
|
24
|
+
'apiVersion' => '0.1',
|
25
|
+
'swaggerVersion' => '1.2',
|
26
|
+
'info' => {},
|
27
|
+
'produces' => ['application/json'],
|
28
|
+
'apis' => [{ 'path' => '/swagger_doc.{format}', 'description' => 'Operations about swagger_docs' }]
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Boolean Params' do
|
4
|
+
def app
|
5
|
+
Class.new(Grape::API) do
|
6
|
+
format :json
|
7
|
+
|
8
|
+
params do
|
9
|
+
requires :a_boolean, type: Virtus::Attribute::Boolean
|
10
|
+
end
|
11
|
+
post :splines do
|
12
|
+
end
|
13
|
+
|
14
|
+
add_swagger_documentation
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
subject do
|
19
|
+
get '/swagger_doc/splines'
|
20
|
+
expect(last_response.status).to eq 200
|
21
|
+
body = JSON.parse last_response.body
|
22
|
+
body['apis'].first['operations'].first['parameters']
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'converts boolean types' do
|
26
|
+
expect(subject).to eq [
|
27
|
+
{ 'paramType' => 'form', 'name' => 'a_boolean', 'description' => nil, 'type' => 'boolean', 'required' => true, 'allowMultiple' => false }
|
28
|
+
]
|
29
|
+
end
|
30
|
+
end
|
data/spec/form_params_spec.rb
CHANGED
@@ -35,52 +35,16 @@ describe 'Form Params' do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
subject do
|
38
|
-
get '/swagger_doc/items
|
38
|
+
get '/swagger_doc/items'
|
39
39
|
JSON.parse(last_response.body)
|
40
40
|
end
|
41
41
|
|
42
42
|
it 'retrieves the documentation form params' do
|
43
|
-
expect(subject['apis']).to eq
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
'summary' => '',
|
50
|
-
'nickname' => 'POST-items---format-',
|
51
|
-
'method' => 'POST',
|
52
|
-
'parameters' => [{ 'paramType' => 'form', 'name' => 'name', 'description' => 'name of item', 'type' => 'string', 'required' => true, 'allowMultiple' => false }],
|
53
|
-
'type' => 'void'
|
54
|
-
}
|
55
|
-
]
|
56
|
-
}, {
|
57
|
-
'path' => '/items/{id}.{format}',
|
58
|
-
'operations' => [
|
59
|
-
{
|
60
|
-
'notes' => '',
|
61
|
-
'summary' => '',
|
62
|
-
'nickname' => 'PUT-items--id---format-',
|
63
|
-
'method' => 'PUT',
|
64
|
-
'parameters' => [
|
65
|
-
{ 'paramType' => 'path', 'name' => 'id', 'description' => 'id of item', 'type' => 'integer', 'required' => true, 'allowMultiple' => false, 'format' => 'int32' },
|
66
|
-
{ 'paramType' => 'form', 'name' => 'name', 'description' => 'name of item', 'type' => 'string', 'required' => true, 'allowMultiple' => false },
|
67
|
-
{ 'paramType' => 'form', 'name' => 'conditions', 'description' => 'conditions of item', 'type' => 'integer', 'required' => true, 'allowMultiple' => false, 'format' => 'int32', 'enum' => [1, 2, 3] }
|
68
|
-
],
|
69
|
-
'type' => 'void'
|
70
|
-
},
|
71
|
-
{
|
72
|
-
'notes' => '',
|
73
|
-
'summary' => '',
|
74
|
-
'nickname' => 'PATCH-items--id---format-',
|
75
|
-
'method' => 'PATCH',
|
76
|
-
'parameters' => [
|
77
|
-
{ 'paramType' => 'path', 'name' => 'id', 'description' => 'id of item', 'type' => 'integer', 'required' => true, 'allowMultiple' => false, 'format' => 'int32' },
|
78
|
-
{ 'paramType' => 'form', 'name' => 'name', 'description' => 'name of item', 'type' => 'string', 'required' => true, 'allowMultiple' => false },
|
79
|
-
{ 'paramType' => 'form', 'name' => 'conditions', 'description' => 'conditions of item', 'type' => 'string', 'required' => false, 'allowMultiple' => false, 'enum' => %w(1 2) }
|
80
|
-
],
|
81
|
-
'type' => 'void'
|
82
|
-
}
|
83
|
-
]
|
84
|
-
}])
|
43
|
+
expect(subject['apis'].count).to eq 2
|
44
|
+
expect(subject['apis'][0]['path']).to start_with '/items'
|
45
|
+
expect(subject['apis'][0]['operations'][0]['method']).to eq 'POST'
|
46
|
+
expect(subject['apis'][1]['path']).to start_with '/items/{id}'
|
47
|
+
expect(subject['apis'][1]['operations'][0]['method']).to eq 'PUT'
|
48
|
+
expect(subject['apis'][1]['operations'][1]['method']).to eq 'PATCH'
|
85
49
|
end
|
86
50
|
end
|
@@ -4,19 +4,11 @@ describe 'helpers' do
|
|
4
4
|
|
5
5
|
before :all do
|
6
6
|
class HelperTestAPI < Grape::API
|
7
|
-
add_swagger_documentation
|
8
7
|
end
|
9
8
|
end
|
10
9
|
|
11
10
|
subject do
|
12
|
-
|
13
|
-
|
14
|
-
# after injecting grape-swagger into the Test API we get the helper methods
|
15
|
-
# back from the first endpoint's class (the API mounted by grape-swagger
|
16
|
-
# to serve the swagger_doc
|
17
|
-
|
18
|
-
api.extend HelperTestAPI.endpoints.first.options[:app].helpers
|
19
|
-
api
|
11
|
+
HelperTestAPI.add_swagger_documentation
|
20
12
|
end
|
21
13
|
|
22
14
|
context 'parsing parameters' do
|
@@ -53,12 +45,6 @@ describe 'helpers' do
|
|
53
45
|
desc: 'rack file',
|
54
46
|
datafile: 'content',
|
55
47
|
required: true
|
56
|
-
},
|
57
|
-
rails: {
|
58
|
-
type: 'Hash',
|
59
|
-
desc: 'rails file',
|
60
|
-
datafile: 'content',
|
61
|
-
required: true
|
62
48
|
}
|
63
49
|
}
|
64
50
|
path = '/coolness'
|
@@ -71,14 +57,6 @@ describe 'helpers' do
|
|
71
57
|
type: 'File',
|
72
58
|
required: true,
|
73
59
|
allowMultiple: false
|
74
|
-
},
|
75
|
-
{
|
76
|
-
paramType: 'body',
|
77
|
-
name: :rails,
|
78
|
-
description: 'rails file',
|
79
|
-
type: 'File',
|
80
|
-
required: true,
|
81
|
-
allowMultiple: false
|
82
60
|
}
|
83
61
|
]
|
84
62
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Group Params' do
|
4
|
+
def app
|
5
|
+
Class.new(Grape::API) do
|
6
|
+
format :json
|
7
|
+
|
8
|
+
params do
|
9
|
+
requires :required_group, type: Hash do
|
10
|
+
requires :required_param_1
|
11
|
+
requires :required_param_2
|
12
|
+
end
|
13
|
+
end
|
14
|
+
post '/groups' do
|
15
|
+
{}
|
16
|
+
end
|
17
|
+
|
18
|
+
add_swagger_documentation
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'retrieves the documentation for group parameters' do
|
23
|
+
get '/swagger_doc/groups'
|
24
|
+
|
25
|
+
body = JSON.parse last_response.body
|
26
|
+
parameters = body['apis'].first['operations'].first['parameters']
|
27
|
+
expect(parameters).to eq [
|
28
|
+
{ 'paramType' => 'form', 'name' => 'required_group[required_param_1]', 'description' => nil, 'type' => 'string', 'required' => true, 'allowMultiple' => false },
|
29
|
+
{ 'paramType' => 'form', 'name' => 'required_group[required_param_2]', 'description' => nil, 'type' => 'string', 'required' => true, 'allowMultiple' => false }]
|
30
|
+
end
|
31
|
+
end
|