grape-swagger 0.10.0 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -43,13 +43,13 @@ describe 'Global Models' do
43
43
  get '/swagger_doc/thing.json'
44
44
  json = JSON.parse(last_response.body)
45
45
  expect(json['models']).to eq(
46
- 'Some::Thing' => {
47
- 'id' => 'Some::Thing',
48
- 'properties' => {
49
- 'text' => { 'type' => 'string', 'description' => 'Content of something.' },
50
- 'name' => { 'type' => 'string', 'description' => 'Name of something.' }
51
- }
52
- })
46
+ 'Some::Thing' => {
47
+ 'id' => 'Some::Thing',
48
+ 'properties' => {
49
+ 'text' => { 'type' => 'string', 'description' => 'Content of something.' },
50
+ 'name' => { 'type' => 'string', 'description' => 'Name of something.' }
51
+ }
52
+ })
53
53
  end
54
54
 
55
55
  it 'uses global models and route endpoint specific entities together' do
@@ -57,21 +57,21 @@ describe 'Global Models' do
57
57
  json = JSON.parse(last_response.body)
58
58
 
59
59
  expect(json['models']).to include(
60
- 'Some::Thing' => {
61
- 'id' => 'Some::Thing',
62
- 'properties' => {
63
- 'text' => { 'type' => 'string', 'description' => 'Content of something.' },
64
- 'name' => { 'type' => 'string', 'description' => 'Name of something.' }
65
- }
66
- })
60
+ 'Some::Thing' => {
61
+ 'id' => 'Some::Thing',
62
+ 'properties' => {
63
+ 'text' => { 'type' => 'string', 'description' => 'Content of something.' },
64
+ 'name' => { 'type' => 'string', 'description' => 'Name of something.' }
65
+ }
66
+ })
67
67
 
68
68
  expect(json['models']).to include(
69
- 'Some::CombinedThing' => {
70
- 'id' => 'Some::CombinedThing',
71
- 'properties' => {
72
- 'text' => { 'type' => 'string', 'description' => 'Content of something.' },
73
- 'created_at' => { 'type' => 'dateTime', 'description' => 'Creation of something.' }
74
- }
75
- })
69
+ 'Some::CombinedThing' => {
70
+ 'id' => 'Some::CombinedThing',
71
+ 'properties' => {
72
+ 'text' => { 'type' => 'string', 'description' => 'Content of something.' },
73
+ 'created_at' => { 'type' => 'string', 'format' => 'date-time', 'description' => 'Creation of something.' }
74
+ }
75
+ })
76
76
  end
77
77
  end
@@ -94,6 +94,13 @@ describe 'API Models' do
94
94
  end
95
95
  end
96
96
 
97
+ module Entities
98
+ class ThingWithRoot < Grape::Entity
99
+ root 'things', 'thing'
100
+ expose :text, documentation: { type: 'string', desc: 'Content of something.' }
101
+ end
102
+ end
103
+
97
104
  def app
98
105
  Class.new(Grape::API) do
99
106
  format :json
@@ -149,6 +156,12 @@ describe 'API Models' do
149
156
  present result, with: Entities::QueryResult
150
157
  end
151
158
 
159
+ desc 'This gets thing_with_root.', entity: Entities::ThingWithRoot
160
+ get '/thing_with_root' do
161
+ thing = OpenStruct.new text: 'thing'
162
+ present thing, with: Entities::ThingWithRoot
163
+ end
164
+
152
165
  add_swagger_documentation
153
166
  end
154
167
  end
@@ -177,6 +190,7 @@ describe 'API Models' do
177
190
  { 'path' => '/aliasedthing.{format}', 'description' => 'Operations about aliasedthings' },
178
191
  { 'path' => '/nesting.{format}', 'description' => 'Operations about nestings' },
179
192
  { 'path' => '/multiple_entities.{format}', 'description' => 'Operations about multiple_entities' },
193
+ { 'path' => '/thing_with_root.{format}', 'description' => 'Operations about thing_with_roots' },
180
194
  { 'path' => '/swagger_doc.{format}', 'description' => 'Operations about swagger_docs' }
181
195
  ]
182
196
  end
@@ -213,68 +227,68 @@ describe 'API Models' do
213
227
  },
214
228
  'required' => ['parts']
215
229
 
216
- )
230
+ )
217
231
 
218
232
  expect(result['models']['ComposedOf']).to include(
219
- 'id' => 'ComposedOf',
220
- 'properties' => {
221
- 'part_text' => {
222
- 'type' => 'string',
223
- 'description' => 'Content of composedof.'
224
- }
225
- }
226
- )
233
+ 'id' => 'ComposedOf',
234
+ 'properties' => {
235
+ 'part_text' => {
236
+ 'type' => 'string',
237
+ 'description' => 'Content of composedof.'
238
+ }
239
+ }
240
+ )
227
241
 
228
242
  expect(result['models']['composed']).to include(
229
- 'id' => 'composed',
230
- 'properties' => {
231
- 'part_text' => {
232
- 'type' => 'string',
233
- 'description' => 'Content of composedof else.'
234
- }
235
-
236
- }
237
- )
243
+ 'id' => 'composed',
244
+ 'properties' => {
245
+ 'part_text' => {
246
+ 'type' => 'string',
247
+ 'description' => 'Content of composedof else.'
248
+ }
249
+
250
+ }
251
+ )
238
252
  end
239
253
 
240
254
  it 'includes enum values in params and documentation.' do
241
255
  get '/swagger_doc/enum_description_in_entity'
242
256
  result = JSON.parse(last_response.body)
243
257
  expect(result['models']['EnumValues']).to eq(
244
- 'id' => 'EnumValues',
245
- 'properties' => {
246
- 'gender' => { 'type' => 'string', 'description' => 'Content of something.', 'enum' => %w(Male Female) },
247
- 'number' => { 'type' => 'integer', 'description' => 'Content of something.', 'enum' => [1, 2] }
248
- }
249
- )
258
+ 'id' => 'EnumValues',
259
+ 'properties' => {
260
+ 'gender' => { 'type' => 'string', 'description' => 'Content of something.', 'enum' => %w(Male Female) },
261
+ 'number' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'Content of something.', 'enum' => [1, 2] }
262
+ }
263
+ )
250
264
 
251
265
  expect(result['apis'][0]['operations'][0]).to include(
252
- 'parameters' =>
253
- [
254
- { 'paramType' => 'query', 'name' => 'gender', 'description' => 'Content of something.', 'type' => 'string', 'required' => false, 'allowMultiple' => false, 'enum' => %w(Male Female) },
255
- { 'paramType' => 'query', 'name' => 'number', 'description' => 'Content of something.', 'type' => 'integer', 'required' => false, 'allowMultiple' => false, 'format' => 'int32', 'enum' => [1, 2] }
256
- ],
257
- 'type' => 'EnumValues'
258
- )
266
+ 'parameters' =>
267
+ [
268
+ { 'paramType' => 'query', 'name' => 'gender', 'description' => 'Content of something.', 'type' => 'string', 'required' => false, 'allowMultiple' => false, 'enum' => %w(Male Female) },
269
+ { 'paramType' => 'query', 'name' => 'number', 'description' => 'Content of something.', 'type' => 'integer', 'required' => false, 'allowMultiple' => false, 'format' => 'int32', 'enum' => [1, 2] }
270
+ ],
271
+ 'type' => 'EnumValues'
272
+ )
259
273
  end
260
274
 
261
275
  it 'includes referenced models in those with aliased references.' do
262
276
  get '/swagger_doc/aliasedthing'
263
277
  result = JSON.parse(last_response.body)
264
278
  expect(result['models']['AliasedThing']).to eq(
265
- 'id' => 'AliasedThing',
266
- 'properties' => {
267
- 'post' => { '$ref' => 'Something', 'description' => 'Reference to something.' }
268
- }
269
- )
279
+ 'id' => 'AliasedThing',
280
+ 'properties' => {
281
+ 'post' => { '$ref' => 'Something', 'description' => 'Reference to something.' }
282
+ }
283
+ )
270
284
 
271
285
  expect(result['models']['Something']).to eq(
272
- 'id' => 'Something',
273
- 'properties' => {
274
- 'text' => { 'type' => 'string', 'description' => 'Content of something.' },
275
- 'links' => { 'type' => 'array', 'items' => { '$ref' => 'link' } }
276
- }
277
- )
286
+ 'id' => 'Something',
287
+ 'properties' => {
288
+ 'text' => { 'type' => 'string', 'description' => 'Content of something.' },
289
+ 'links' => { 'type' => 'array', 'items' => { '$ref' => 'link' } }
290
+ }
291
+ )
278
292
  end
279
293
 
280
294
  it 'includes all entities with four levels of nesting' do
@@ -290,4 +304,10 @@ describe 'API Models' do
290
304
 
291
305
  expect(result['models']).to include('QueryInput', 'QueryInputElement', 'QueryResult')
292
306
  end
307
+
308
+ it 'includes an id equal to the model name' do
309
+ get '/swagger_doc/thing_with_root'
310
+ result = JSON.parse(last_response.body)
311
+ expect(result['models']['thing']['id']).to eq('thing')
312
+ end
293
313
  end
@@ -62,3 +62,67 @@ describe 'simple api with prefix' do
62
62
  end
63
63
  end
64
64
  end
65
+
66
+ describe 'simple api with partially same path as docs mount and hidden doc path' do
67
+ before :all do
68
+ class SamePathApi < Grape::API
69
+ desc 'This gets the documents'
70
+ get '/documents' do
71
+ { test: 'something' }
72
+ end
73
+
74
+ desc 'This gets the doc types'
75
+ get '/doc-types' do
76
+ { test: 'something' }
77
+ end
78
+ end
79
+
80
+ class SimpleSamePathApi < Grape::API
81
+ mount SamePathApi
82
+ add_swagger_documentation(
83
+ mount_path: '/doc',
84
+ hide_documentation_path: true
85
+ )
86
+ end
87
+ end
88
+
89
+ def app
90
+ SimpleSamePathApi
91
+ end
92
+
93
+ it 'retrieves swagger-documentation on /doc that contains documents' do
94
+ get '/doc.json'
95
+ expect(JSON.parse(last_response.body)).to eq(
96
+ 'apiVersion' => '0.1',
97
+ 'swaggerVersion' => '1.2',
98
+ 'info' => {},
99
+ 'produces' => Grape::ContentTypes::CONTENT_TYPES.values.uniq,
100
+ 'apis' => [
101
+ { 'path' => '/documents.{format}', 'description' => 'Operations about documents' },
102
+ { 'path' => '/doc-types.{format}', 'description' => 'Operations about doc-types' }
103
+ ]
104
+ )
105
+ end
106
+
107
+ it 'retrieves the documentation for apis' do
108
+ get '/doc/documents.json'
109
+ expect(JSON.parse(last_response.body)).to eq(
110
+ 'apiVersion' => '0.1',
111
+ 'swaggerVersion' => '1.2',
112
+ 'basePath' => 'http://example.org',
113
+ 'resourcePath' => '/documents',
114
+ 'produces' => Grape::ContentTypes::CONTENT_TYPES.values.uniq,
115
+ 'apis' => [{
116
+ 'path' => '/documents.{format}',
117
+ 'operations' => [{
118
+ 'notes' => '',
119
+ 'summary' => 'This gets the documents',
120
+ 'nickname' => 'GET-documents---format-',
121
+ 'method' => 'GET',
122
+ 'parameters' => [],
123
+ 'type' => 'void'
124
+ }]
125
+ }]
126
+ )
127
+ end
128
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'API with minimally documented models' do
4
+ def app
5
+ entity_klass = Class.new do
6
+ def self.exposures
7
+ {}
8
+ end
9
+
10
+ def self.documentation
11
+ {
12
+ bar: { type: String },
13
+ foo: {}
14
+ }
15
+ end
16
+
17
+ def self.entity_name
18
+ 'Foo'
19
+ end
20
+ end
21
+
22
+ Class.new(Grape::API) do
23
+ format :json
24
+
25
+ get :foo do
26
+ end
27
+
28
+ add_swagger_documentation \
29
+ format: :json,
30
+ models: [Class.new(entity_klass)]
31
+ end
32
+ end
33
+
34
+ subject do
35
+ get '/swagger_doc/foo'
36
+ JSON.parse(last_response.body)['models']
37
+ end
38
+
39
+ it 'returns model' do
40
+ expect(subject).to eq(
41
+ 'Foo' => {
42
+ 'id' => 'Foo',
43
+ 'properties' => {
44
+ 'bar' => { 'type' => 'string' },
45
+ 'foo' => { '$ref' => nil }
46
+ }
47
+ }
48
+ )
49
+ end
50
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'API with Prefix and Namespace' do
4
+ def app
5
+ Class.new(Grape::API) do
6
+ format :json
7
+ prefix 'api'
8
+
9
+ namespace :status do
10
+ desc 'Retrieve status.'
11
+ get do
12
+ end
13
+ end
14
+
15
+ add_swagger_documentation
16
+ end
17
+ end
18
+
19
+ subject do
20
+ get '/api/swagger_doc'
21
+ expect(last_response.status).to eq 200
22
+ body = JSON.parse last_response.body
23
+ body['apis']
24
+ end
25
+
26
+ it 'gets array types' do
27
+ expect(subject).to eq([
28
+ { 'path' => '/status.{format}', 'description' => 'Operations about statuses' },
29
+ { 'path' => '/swagger_doc.{format}', 'description' => 'Operations about swagger_docs' }
30
+ ])
31
+ end
32
+ end
@@ -47,14 +47,14 @@ describe 'Standalone namespace API' do
47
47
 
48
48
  it 'that contains all api paths' do
49
49
  expect(json_body['apis']).to eq(
50
- [
51
- { 'path' => '/store.{format}', 'description' => 'Operations about stores' },
52
- { 'path' => '/store_orders.{format}', 'description' => 'Operations about store/orders' },
53
- { 'path' => '/store_orders_actions2.{format}', 'description' => 'Operations about store/orders/actions2s' },
54
- { 'path' => '/specific-store-orders.{format}', 'description' => 'Operations about store/:store_id/orders' },
55
- { 'path' => '/swagger_doc.{format}', 'description' => 'Operations about swagger_docs' }
56
- ]
57
- )
50
+ [
51
+ { 'path' => '/store.{format}', 'description' => 'Operations about stores' },
52
+ { 'path' => '/store_orders.{format}', 'description' => 'Operations about store/orders' },
53
+ { 'path' => '/store_orders_actions2.{format}', 'description' => 'Operations about store/orders/actions2s' },
54
+ { 'path' => '/specific-store-orders.{format}', 'description' => 'Operations about store/:store_id/orders' },
55
+ { 'path' => '/swagger_doc.{format}', 'description' => 'Operations about swagger_docs' }
56
+ ]
57
+ )
58
58
  end
59
59
  end
60
60
 
@@ -152,14 +152,14 @@ describe 'Standalone namespace API' do
152
152
 
153
153
  it 'that contains all api paths' do
154
154
  expect(json_body['apis']).to eq(
155
- [
156
- { 'path' => '/store.{format}', 'description' => 'Operations about stores' },
157
- { 'path' => '/store_orders.{format}', 'description' => 'Operations about store/orders' },
158
- { 'path' => '/store_orders_actions2.{format}', 'description' => 'Operations about store/orders/actions2s' },
159
- { 'path' => '/specific-store-orders.{format}', 'description' => 'Operations about store/:store_id/orders' },
160
- { 'path' => '/swagger_doc.{format}', 'description' => 'Operations about swagger_docs' }
161
- ]
162
- )
155
+ [
156
+ { 'path' => '/store.{format}', 'description' => 'Operations about stores' },
157
+ { 'path' => '/store_orders.{format}', 'description' => 'Operations about store/orders' },
158
+ { 'path' => '/store_orders_actions2.{format}', 'description' => 'Operations about store/orders/actions2s' },
159
+ { 'path' => '/specific-store-orders.{format}', 'description' => 'Operations about store/:store_id/orders' },
160
+ { 'path' => '/swagger_doc.{format}', 'description' => 'Operations about swagger_docs' }
161
+ ]
162
+ )
163
163
  end
164
164
  end
165
165
 
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Array Entity' do
4
+ before :all do
5
+ class Something < Grape::Entity
6
+ expose :text, documentation: { type: 'string', desc: 'Content of something.' }
7
+ end
8
+ end
9
+
10
+ def app
11
+ Class.new(Grape::API) do
12
+ format :json
13
+
14
+ desc 'This returns something or an error',
15
+ is_array: true,
16
+ entity: Something
17
+ post :action do
18
+ end
19
+
20
+ add_swagger_documentation
21
+ end
22
+ end
23
+
24
+ subject do
25
+ get '/swagger_doc/action'
26
+ JSON.parse(last_response.body)
27
+ end
28
+
29
+ it 'reads param type correctly' do
30
+ expect(subject['models'].keys).to include 'Something'
31
+ expect(subject['apis'][0]['operations'][0]['type']).to eq('array')
32
+ expect(subject['apis'][0]['operations'][0]['items']).to eq('$ref' => 'Something')
33
+ end
34
+ end
@@ -14,21 +14,50 @@ describe 'Array Params' do
14
14
  post :splines do
15
15
  end
16
16
 
17
+ params do
18
+ optional :raw_array, type: Array
19
+ end
20
+ get :raw_array_splines do
21
+ end
22
+
23
+ params do
24
+ optional :raw_array, type: Array[Integer]
25
+ end
26
+ get :raw_array_integers do
27
+ end
28
+
17
29
  add_swagger_documentation
18
30
  end
19
31
  end
20
32
 
21
- subject do
33
+ it 'gets array types' do
22
34
  get '/swagger_doc/splines'
23
35
  expect(last_response.status).to eq 200
24
36
  body = JSON.parse last_response.body
25
- body['apis'].first['operations'].first['parameters']
26
- end
27
-
28
- it 'gets array types' do
29
- expect(subject).to eq [
37
+ parameters = body['apis'].first['operations'].first['parameters']
38
+ expect(parameters).to eq [
30
39
  { 'paramType' => 'form', 'name' => 'a_array[][param_1]', 'description' => nil, 'type' => 'integer', 'required' => true, 'allowMultiple' => false, 'format' => 'int32' },
31
40
  { 'paramType' => 'form', 'name' => 'a_array[][param_2]', 'description' => nil, 'type' => 'string', 'required' => true, 'allowMultiple' => false }
32
41
  ]
33
42
  end
43
+
44
+ it 'get raw array type' do
45
+ get '/swagger_doc/raw_array_splines'
46
+ expect(last_response.status).to eq 200
47
+ body = JSON.parse last_response.body
48
+ parameters = body['apis'].first['operations'].first['parameters']
49
+ expect(parameters).to eq [
50
+ { 'paramType' => 'query', 'name' => 'raw_array', 'description' => nil, 'type' => 'Array', 'required' => false, 'allowMultiple' => false }
51
+ ]
52
+ end
53
+
54
+ it 'get raw array integer' do
55
+ get '/swagger_doc/raw_array_integers'
56
+ expect(last_response.status).to eq 200
57
+ body = JSON.parse last_response.body
58
+ parameters = body['apis'].first['operations'].first['parameters']
59
+ expect(parameters).to eq [
60
+ { 'paramType' => 'query', 'name' => 'raw_array', 'description' => nil, 'type' => 'array', 'required' => false, 'allowMultiple' => false, 'items' => { 'type' => 'integer', 'format' => 'int32' } }
61
+ ]
62
+ end
34
63
  end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'grape_version'
2
3
 
3
4
  describe 'Default API' do
4
5
  context 'with no additional options' do
@@ -38,6 +39,47 @@ describe 'Default API' do
38
39
  end
39
40
  end
40
41
  end
42
+
43
+ end
44
+ context 'with additional option block given to desc', if: GrapeVersion.satisfy?('>= 0.12.0') do
45
+ def app
46
+ Class.new(Grape::API) do
47
+ format :json
48
+ desc 'This gets something.' do
49
+ detail 'more details about the endpoint'
50
+ end
51
+ get '/something' do
52
+ { bla: 'something' }
53
+ end
54
+ add_swagger_documentation
55
+ end
56
+ end
57
+
58
+ subject do
59
+ get '/swagger_doc/something'
60
+ JSON.parse(last_response.body)
61
+ end
62
+
63
+ it 'documents endpoint' do
64
+ expect(subject).to eq(
65
+ 'apiVersion' => '0.1',
66
+ 'swaggerVersion' => '1.2',
67
+ 'basePath' => 'http://example.org',
68
+ 'produces' => ['application/json'],
69
+ 'resourcePath' => '/something',
70
+ 'apis' => [{
71
+ 'path' => '/something.{format}',
72
+ 'operations' => [{
73
+ 'notes' => 'more details about the endpoint',
74
+ 'summary' => 'This gets something.',
75
+ 'nickname' => 'GET-something--json-',
76
+ 'method' => 'GET',
77
+ 'parameters' => [],
78
+ 'type' => 'void'
79
+ }]
80
+ }]
81
+ )
82
+ end
41
83
  end
42
84
 
43
85
  context 'with additional info' do
@@ -24,7 +24,7 @@ describe 'Float Params' do
24
24
 
25
25
  it 'converts float types' do
26
26
  expect(subject).to eq [
27
- { 'paramType' => 'form', 'name' => 'a_float', 'description' => nil, 'type' => 'float', 'required' => true, 'allowMultiple' => false }
27
+ { 'paramType' => 'form', 'name' => 'a_float', 'description' => nil, 'type' => 'number', 'format' => 'float', 'required' => true, 'allowMultiple' => false }
28
28
  ]
29
29
  end
30
30
  end
@@ -24,6 +24,19 @@ describe 'helpers' do
24
24
  ]
25
25
  end
26
26
 
27
+ it 'parses params as query strings for a GET with an example' do
28
+ params = {
29
+ name: { type: 'String', desc: 'A name', required: true, default: 'default api value', documentation: { example: 'default swagger value' } },
30
+ level: 'max'
31
+ }
32
+ path = '/coolness'
33
+ method = 'GET'
34
+ expect(subject.parse_params(params, path, method)).to eq [
35
+ { paramType: 'query', name: :name, description: 'A name', type: 'string', required: true, allowMultiple: false, defaultValue: 'default swagger value' },
36
+ { paramType: 'query', name: :level, description: '', type: 'string', required: false, allowMultiple: false }
37
+ ]
38
+ end
39
+
27
40
  it 'parses params as form for a POST' do
28
41
  params = {
29
42
  name: { type: 'String', desc: 'A name', required: true },
@@ -132,7 +145,7 @@ describe 'helpers' do
132
145
  'XAuthToken' => { description: 'A required header.', required: true, default: 'default' }
133
146
  }
134
147
  expect(subject.parse_header_params(params)).to eq [
135
- { paramType: 'header', name: 'XAuthToken', description: 'A required header.', type: 'String', required: true, defaultValue: 'default' }
148
+ { paramType: 'header', name: 'XAuthToken', description: 'A required header.', type: 'string', required: true, defaultValue: 'default' }
136
149
  ]
137
150
  end
138
151
  end