grape-swagger 0.21.0 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/.rubocop_todo.yml +1 -1
  4. data/CHANGELOG.md +24 -2
  5. data/Gemfile +5 -0
  6. data/README.md +105 -3
  7. data/example/api/endpoints.rb +16 -16
  8. data/lib/grape-swagger.rb +0 -1
  9. data/lib/grape-swagger/doc_methods.rb +1 -0
  10. data/lib/grape-swagger/doc_methods/data_type.rb +15 -3
  11. data/lib/grape-swagger/doc_methods/extensions.rb +16 -12
  12. data/lib/grape-swagger/doc_methods/move_params.rb +139 -94
  13. data/lib/grape-swagger/doc_methods/parse_params.rb +9 -7
  14. data/lib/grape-swagger/endpoint.rb +36 -17
  15. data/lib/grape-swagger/version.rb +1 -1
  16. data/spec/lib/data_type_spec.rb +24 -0
  17. data/spec/lib/endpoint_spec.rb +13 -0
  18. data/spec/lib/move_params_spec.rb +124 -116
  19. data/spec/support/model_parsers/entity_parser.rb +8 -2
  20. data/spec/support/model_parsers/mock_parser.rb +10 -0
  21. data/spec/support/model_parsers/representable_parser.rb +7 -0
  22. data/spec/support/the_paths_definitions.rb +1 -2
  23. data/spec/swagger_v2/api_swagger_v2_definitions-models_spec.rb +2 -1
  24. data/spec/swagger_v2/api_swagger_v2_detail_spec.rb +1 -1
  25. data/spec/swagger_v2/api_swagger_v2_extensions_spec.rb +22 -1
  26. data/spec/swagger_v2/api_swagger_v2_global_configuration_spec.rb +4 -1
  27. data/spec/swagger_v2/api_swagger_v2_hash_and_array_spec.rb +60 -0
  28. data/spec/swagger_v2/api_swagger_v2_headers_spec.rb +14 -9
  29. data/spec/swagger_v2/api_swagger_v2_hide_param_spec.rb +90 -0
  30. data/spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb +185 -110
  31. data/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb +11 -13
  32. data/spec/swagger_v2/api_swagger_v2_response_spec.rb +5 -5
  33. data/spec/swagger_v2/endpoint_versioned_path_spec.rb +19 -18
  34. data/spec/swagger_v2/namespaced_api_spec.rb +20 -0
  35. data/spec/swagger_v2/param_multi_type_spec.rb +73 -0
  36. data/spec/swagger_v2/param_type_spec.rb +54 -27
  37. data/spec/swagger_v2/params_array_spec.rb +96 -6
  38. data/spec/swagger_v2/params_nested_spec.rb +2 -2
  39. metadata +9 -3
@@ -72,7 +72,7 @@ describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `h
72
72
  specify do
73
73
  expect(subject['paths']['/wo_entities/in_body']['post']['parameters']).to eql(
74
74
  [
75
- { 'name' => 'postWoEntitiesInBody', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/postWoEntitiesInBody' } }
75
+ { 'name' => 'WoEntitiesInBody', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/postWoEntitiesInBody' } }
76
76
  ]
77
77
  )
78
78
  end
@@ -94,17 +94,16 @@ describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `h
94
94
  expect(subject['paths']['/wo_entities/in_body/{key}']['put']['parameters']).to eql(
95
95
  [
96
96
  { 'in' => 'path', 'name' => 'key', 'type' => 'integer', 'format' => 'int32', 'required' => true },
97
- { 'name' => 'putWoEntitiesInBodyKey', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/putWoEntitiesInBodyKey' } }
97
+ { 'name' => 'WoEntitiesInBody', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/putWoEntitiesInBody' } }
98
98
  ]
99
99
  )
100
100
  end
101
101
 
102
102
  specify do
103
- expect(subject['definitions']['putWoEntitiesInBodyKey']).to eql(
103
+ expect(subject['definitions']['putWoEntitiesInBody']).to eql(
104
104
  'description' => 'put in body /wo entity',
105
105
  'type' => 'object',
106
106
  'properties' => {
107
- 'key' => { 'type' => 'integer', 'format' => 'int32', 'readOnly' => true },
108
107
  'in_body_1' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'in_body_1' },
109
108
  'in_body_2' => { 'type' => 'string', 'description' => 'in_body_2' },
110
109
  'in_body_3' => { 'type' => 'string', 'description' => 'in_body_3' }
@@ -122,19 +121,19 @@ describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `h
122
121
  specify do
123
122
  expect(subject['paths']['/with_entities/in_body']['post']['parameters']).to eql(
124
123
  [
125
- { 'name' => 'ResponseItem', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/postRequestResponseItem' } }
124
+ { 'name' => 'WithEntitiesInBody', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/postWithEntitiesInBody' } }
126
125
  ]
127
126
  )
128
127
  end
129
128
 
130
129
  specify do
131
- expect(subject['definitions']['postRequestResponseItem']).to eql(
132
- 'description' => 'post in body with entity',
130
+ expect(subject['definitions']['postWithEntitiesInBody']).to eql(
133
131
  'type' => 'object',
134
132
  'properties' => {
135
133
  'name' => { 'type' => 'string', 'description' => 'name' }
136
134
  },
137
- 'required' => ['name']
135
+ 'required' => ['name'],
136
+ 'description' => 'post in body with entity'
138
137
  )
139
138
  end
140
139
 
@@ -142,19 +141,18 @@ describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `h
142
141
  expect(subject['paths']['/with_entities/in_body/{id}']['put']['parameters']).to eql(
143
142
  [
144
143
  { 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true },
145
- { 'name' => 'ResponseItem', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/putRequestResponseItem' } }
144
+ { 'name' => 'WithEntitiesInBody', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/putWithEntitiesInBody' } }
146
145
  ]
147
146
  )
148
147
  end
149
148
 
150
149
  specify do
151
- expect(subject['definitions']['putRequestResponseItem']).to eql(
152
- 'description' => 'put in body with entity',
150
+ expect(subject['definitions']['putWithEntitiesInBody']).to eql(
153
151
  'type' => 'object',
154
152
  'properties' => {
155
- 'id' => { 'type' => 'integer', 'format' => 'int32', 'readOnly' => true },
156
153
  'name' => { 'type' => 'string', 'description' => 'name' }
157
- }
154
+ },
155
+ 'description' => 'put in body with entity'
158
156
  )
159
157
  end
160
158
  end
@@ -11,7 +11,7 @@ describe 'response' do
11
11
  desc 'This returns something',
12
12
  params: Entities::UseResponse.documentation,
13
13
  failure: [{ code: 400, message: 'NotFound', model: Entities::ApiError }]
14
- post '/params_response' do
14
+ post '/params_given' do
15
15
  { 'declared_params' => declared(params) }
16
16
  end
17
17
 
@@ -83,12 +83,12 @@ describe 'response' do
83
83
 
84
84
  describe 'uses params as response object' do
85
85
  subject do
86
- get '/swagger_doc/params_response'
86
+ get '/swagger_doc/params_given'
87
87
  JSON.parse(last_response.body)
88
88
  end
89
89
 
90
90
  specify do
91
- expect(subject['paths']['/params_response']['post']).to eql(
91
+ expect(subject['paths']['/params_given']['post']).to eql(
92
92
  'summary' => 'This returns something',
93
93
  'description' => 'This returns something',
94
94
  'produces' => ['application/json'],
@@ -101,8 +101,8 @@ describe 'response' do
101
101
  '201' => { 'description' => 'This returns something' },
102
102
  '400' => { 'description' => 'NotFound', 'schema' => { '$ref' => '#/definitions/ApiError' } }
103
103
  },
104
- 'tags' => ['params_response'],
105
- 'operationId' => 'postParamsResponse'
104
+ 'tags' => ['params_given'],
105
+ 'operationId' => 'postParamsGiven'
106
106
  )
107
107
  expect(subject['definitions']).to eql(swagger_params_as_response_object)
108
108
  end
@@ -1,30 +1,31 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Grape::Endpoint#path_and_definitions' do
4
- before do
5
- module API
6
- module V1
7
- class Item < Grape::API
8
- version 'v1', using: :path
4
+ let(:api) do
5
+ item = Class.new(Grape::API) do
6
+ version 'v1', using: :path
9
7
 
10
- resource :item do
11
- get '/'
12
- end
13
- end
14
- end
15
-
16
- class Root < Grape::API
17
- mount API::V1::Item
18
- add_swagger_documentation add_version: true
8
+ resource :item do
9
+ get '/'
19
10
  end
20
11
  end
21
12
 
22
- @options = { add_version: true }
23
- @target_routes = API::Root.combined_namespace_routes
13
+ Class.new(Grape::API) do
14
+ mount item
15
+ add_swagger_documentation add_version: true
16
+ end
24
17
  end
25
18
 
19
+ let(:options) { { add_version: true } }
20
+ let(:target_routes) { api.combined_namespace_routes }
21
+
22
+ subject { api.endpoints[0].path_and_definition_objects(target_routes, options) }
23
+
26
24
  it 'is returning a versioned path' do
27
- expect(API::V1::Item.endpoints[0]
28
- .path_and_definition_objects(@target_routes, @options)[0].keys[0]).to eql '/v1/item'
25
+ expect(subject[0].keys[0]).to eq '/v1/item'
26
+ end
27
+
28
+ it 'tags the endpoint with the resource name' do
29
+ expect(subject.first['/v1/item'][:get][:tags]).to eq ['item']
29
30
  end
30
31
  end
@@ -21,6 +21,26 @@ describe 'namespace' do
21
21
  end
22
22
  end
23
23
 
24
+ context 'with camel case namespace' do
25
+ def app
26
+ Class.new(Grape::API) do
27
+ namespace :camelCases do
28
+ get '/', desc: 'Look! An endpoint.'
29
+ end
30
+ add_swagger_documentation format: :json
31
+ end
32
+ end
33
+
34
+ subject do
35
+ get '/swagger_doc'
36
+ JSON.parse(last_response.body)['paths']['/camelCases']['get']
37
+ end
38
+
39
+ it 'shows the namespace description in the json spec' do
40
+ expect(subject['description']).to eql('Look! An endpoint.')
41
+ end
42
+ end
43
+
24
44
  context 'mounted' do
25
45
  def app
26
46
  namespaced_api = Class.new(Grape::API) do
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Params Multi Types' do
4
+ def app
5
+ Class.new(Grape::API) do
6
+ format :json
7
+
8
+ params do
9
+ if Grape::VERSION < '0.14'
10
+ requires :input, type: [String, Integer]
11
+ else
12
+ requires :input, types: [String, Integer]
13
+ end
14
+ requires :another_input, type: [String, Integer]
15
+ end
16
+ post :action do
17
+ end
18
+
19
+ add_swagger_documentation
20
+ end
21
+ end
22
+
23
+ subject do
24
+ get '/swagger_doc/action'
25
+ expect(last_response.status).to eq 200
26
+ body = JSON.parse last_response.body
27
+ body['paths']['/action']['post']['parameters']
28
+ end
29
+
30
+ it 'reads param type correctly' do
31
+ expect(subject).to eq [
32
+ {
33
+ 'in' => 'formData',
34
+ 'name' => 'input',
35
+ 'type' => 'string',
36
+ 'required' => true
37
+ },
38
+ {
39
+ 'in' => 'formData',
40
+ 'name' => 'another_input',
41
+ 'type' => 'string',
42
+ 'required' => true
43
+ }
44
+ ]
45
+ end
46
+
47
+ describe 'header params' do
48
+ def app
49
+ Class.new(Grape::API) do
50
+ format :json
51
+
52
+ desc 'Some API', headers: { 'My-Header' => { required: true, description: 'Set this!' } }
53
+ params do
54
+ if Grape::VERSION < '0.14'
55
+ requires :input, type: [String, Integer]
56
+ else
57
+ requires :input, types: [String, Integer]
58
+ end
59
+ requires :another_input, type: [String, Integer]
60
+ end
61
+ post :action do
62
+ end
63
+
64
+ add_swagger_documentation
65
+ end
66
+ end
67
+
68
+ it 'has consistent types' do
69
+ types = subject.map { |param| param['type'] }
70
+ expect(types).to eq(%w(string string string))
71
+ end
72
+ end
73
+ end
@@ -11,45 +11,72 @@ describe 'Params Types' do
11
11
  post :action do
12
12
  end
13
13
 
14
+ params do
15
+ requires :input, type: String, default: '14', documentation: { type: 'email', default: '42' }
16
+ end
17
+ post :action_with_doc do
18
+ end
19
+
14
20
  add_swagger_documentation
15
21
  end
16
22
  end
23
+ context 'with no documentation hash' do
24
+ subject do
25
+ get '/swagger_doc/action'
26
+ expect(last_response.status).to eq 200
27
+ body = JSON.parse last_response.body
28
+ body['paths']['/action']['post']['parameters']
29
+ end
17
30
 
18
- subject do
19
- get '/swagger_doc/action'
20
- expect(last_response.status).to eq 200
21
- body = JSON.parse last_response.body
22
- body['paths']['/action']['post']['parameters']
23
- end
31
+ it 'reads param type correctly' do
32
+ expect(subject).to eq [{
33
+ 'in' => 'formData',
34
+ 'name' => 'input',
35
+ 'type' => 'string',
36
+ 'required' => true
37
+ }]
38
+ end
24
39
 
25
- it 'reads param type correctly' do
26
- expect(subject).to eq [{
27
- 'in' => 'formData',
28
- 'name' => 'input',
29
- 'type' => 'string',
30
- 'required' => true
31
- }]
32
- end
40
+ describe 'header params' do
41
+ def app
42
+ Class.new(Grape::API) do
43
+ format :json
33
44
 
34
- describe 'header params' do
35
- def app
36
- Class.new(Grape::API) do
37
- format :json
45
+ desc 'Some API', headers: { 'My-Header' => { required: true, description: 'Set this!' } }
46
+ params do
47
+ requires :input, type: String
48
+ end
49
+ post :action do
50
+ end
38
51
 
39
- desc 'Some API', headers: { 'My-Header' => { required: true, description: 'Set this!' } }
40
- params do
41
- requires :input, type: String
42
- end
43
- post :action do
52
+ add_swagger_documentation
44
53
  end
54
+ end
45
55
 
46
- add_swagger_documentation
56
+ it 'has consistent types' do
57
+ types = subject.map { |param| param['type'] }
58
+ expect(types).to eq(%w(string string))
47
59
  end
48
60
  end
61
+ end
62
+
63
+ context 'with documentation hash' do
64
+ subject do
65
+ get '/swagger_doc/action_with_doc'
66
+ expect(last_response.status).to eq 200
67
+ body = JSON.parse last_response.body
68
+ body['paths']['/action_with_doc']['post']['parameters']
69
+ end
49
70
 
50
- it 'has consistent types' do
51
- types = subject.map { |param| param['type'] }
52
- expect(types).to eq(%w(string string))
71
+ it 'reads param type correctly' do
72
+ expect(subject).to eq [{
73
+ 'in' => 'formData',
74
+ 'name' => 'input',
75
+ 'type' => 'string',
76
+ 'format' => 'email',
77
+ 'default' => '42',
78
+ 'required' => true
79
+ }]
53
80
  end
54
81
  end
55
82
  end
@@ -27,6 +27,36 @@ describe 'Group Params as Array' do
27
27
  { 'declared_params' => declared(params) }
28
28
  end
29
29
 
30
+ # as body parameters it would be interpreted a bit different,
31
+ # cause it could not be distinguished anymore, so this would be translated to one array,
32
+ # see also next example for the difference
33
+ params do
34
+ requires :array_of_string, type: Array[String], documentation: { param_type: 'body', desc: 'nested array of strings' }
35
+ requires :array_of_integer, type: Array[Integer], documentation: { param_type: 'body', desc: 'nested array of integers' }
36
+ end
37
+
38
+ post '/array_of_type' do
39
+ { 'declared_params' => declared(params) }
40
+ end
41
+
42
+ params do
43
+ requires :array_of_string, type: Array[String], documentation: { param_type: 'body', desc: 'array of strings' }
44
+ requires :integer_value, type: Integer, documentation: { param_type: 'body', desc: 'integer value' }
45
+ end
46
+
47
+ post '/object_and_array' do
48
+ { 'declared_params' => declared(params) }
49
+ end
50
+
51
+ params do
52
+ requires :array_of_string, type: Array[String]
53
+ requires :array_of_integer, type: Array[Integer]
54
+ end
55
+
56
+ post '/array_of_type_in_form' do
57
+ { 'declared_params' => declared(params) }
58
+ end
59
+
30
60
  add_swagger_documentation
31
61
  end
32
62
  end
@@ -40,8 +70,8 @@ describe 'Group Params as Array' do
40
70
  specify do
41
71
  expect(subject['paths']['/groups']['post']['parameters']).to eql(
42
72
  [
43
- { 'in' => 'formData', 'name' => 'required_group[][required_param_1]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } },
44
- { 'in' => 'formData', 'name' => 'required_group[][required_param_2]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } }
73
+ { 'in' => 'formData', 'name' => 'required_group[required_param_1]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } },
74
+ { 'in' => 'formData', 'name' => 'required_group[required_param_2]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } }
45
75
  ]
46
76
  )
47
77
  end
@@ -56,10 +86,70 @@ describe 'Group Params as Array' do
56
86
  specify do
57
87
  expect(subject['paths']['/type_given']['post']['parameters']).to eql(
58
88
  [
59
- { 'in' => 'formData', 'name' => 'typed_group[][id]', 'description' => 'integer given', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'integer' } },
60
- { 'in' => 'formData', 'name' => 'typed_group[][name]', 'description' => 'string given', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } },
61
- { 'in' => 'formData', 'name' => 'typed_group[][email]', 'description' => 'email given', 'required' => false, 'type' => 'array', 'items' => { 'type' => 'string' } },
62
- { 'in' => 'formData', 'name' => 'typed_group[][others]', 'required' => false, 'type' => 'array', 'items' => { 'type' => 'integer' }, 'enum' => [1, 2, 3] }
89
+ { 'in' => 'formData', 'name' => 'typed_group[id]', 'description' => 'integer given', 'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' }, 'required' => true },
90
+ { 'in' => 'formData', 'name' => 'typed_group[name]', 'description' => 'string given', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true },
91
+ { 'in' => 'formData', 'name' => 'typed_group[email]', 'description' => 'email given', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => false },
92
+ { 'in' => 'formData', 'name' => 'typed_group[others]', 'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' }, 'enum' => [1, 2, 3], 'required' => false }
93
+ ]
94
+ )
95
+ end
96
+ end
97
+
98
+ describe 'retrieves the documentation for parameters that are arrays of primitive types' do
99
+ subject do
100
+ get '/swagger_doc/array_of_type'
101
+ JSON.parse(last_response.body)
102
+ end
103
+
104
+ specify do
105
+ expect(subject['definitions']['postArrayOfType']['type']).to eql 'array'
106
+ expect(subject['definitions']['postArrayOfType']['items']).to eql(
107
+ 'type' => 'object',
108
+ 'properties' => {
109
+ 'array_of_string' => {
110
+ 'type' => 'string', 'description' => 'nested array of strings'
111
+ },
112
+ 'array_of_integer' => {
113
+ 'type' => 'integer', 'format' => 'int32', 'description' => 'nested array of integers'
114
+ }
115
+ },
116
+ 'required' => %w(array_of_string array_of_integer)
117
+ )
118
+ end
119
+ end
120
+
121
+ describe 'documentation for simple and array parameters' do
122
+ subject do
123
+ get '/swagger_doc/object_and_array'
124
+ JSON.parse(last_response.body)
125
+ end
126
+
127
+ specify do
128
+ expect(subject['definitions']['postObjectAndArray']['type']).to eql 'object'
129
+ expect(subject['definitions']['postObjectAndArray']['properties']).to eql(
130
+ 'array_of_string' => {
131
+ 'type' => 'array', 'items' => {
132
+ 'type' => 'string', 'description' => 'array of strings'
133
+ }
134
+ },
135
+ 'integer_value' => {
136
+ 'type' => 'integer', 'format' => 'int32', 'description' => 'integer value'
137
+ }
138
+ )
139
+ end
140
+ end
141
+
142
+ describe 'retrieves the documentation for typed group parameters' do
143
+ subject do
144
+ get '/swagger_doc/array_of_type_in_form'
145
+ JSON.parse(last_response.body)
146
+ end
147
+
148
+ specify do
149
+ expect(subject['paths']['/array_of_type_in_form']['post']['parameters']).to eql(
150
+ [
151
+ { 'in' => 'formData', 'name' => 'array_of_string', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true },
152
+ { 'in' => 'formData', 'name' => 'array_of_integer', 'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' }, 'required' => true }
63
153
  ]
64
154
  )
65
155
  end