grape-swagger 0.20.3 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +10 -10
  3. data/.travis.yml +8 -3
  4. data/CHANGELOG.md +27 -0
  5. data/Gemfile +2 -0
  6. data/README.md +111 -12
  7. data/UPGRADING.md +9 -0
  8. data/grape-swagger.gemspec +1 -3
  9. data/lib/grape-swagger.rb +8 -1
  10. data/lib/grape-swagger/doc_methods/optional_object.rb +14 -2
  11. data/lib/grape-swagger/doc_methods/parse_params.rb +3 -4
  12. data/lib/grape-swagger/doc_methods/path_string.rb +4 -3
  13. data/lib/grape-swagger/endpoint.rb +25 -55
  14. data/lib/grape-swagger/errors.rb +3 -0
  15. data/lib/grape-swagger/grape/route.rb +2 -1
  16. data/lib/grape-swagger/model_parsers.rb +33 -0
  17. data/lib/grape-swagger/version.rb +1 -1
  18. data/spec/issues/403_versions_spec.rb +20 -4
  19. data/spec/lib/model_parsers_spec.rb +102 -0
  20. data/spec/lib/optional_object_spec.rb +15 -11
  21. data/spec/lib/path_string_spec.rb +72 -18
  22. data/spec/lib/produces_consumes_spec.rb +10 -5
  23. data/spec/spec_helper.rb +4 -2
  24. data/spec/support/empty_model_parser.rb +20 -0
  25. data/spec/support/mock_parser.rb +22 -0
  26. data/spec/support/model_parsers/entity_parser.rb +325 -0
  27. data/spec/support/{api_swagger_v2_result.rb → model_parsers/mock_parser.rb} +186 -60
  28. data/spec/support/model_parsers/representable_parser.rb +394 -0
  29. data/spec/support/the_paths_definitions.rb +7 -3
  30. data/spec/swagger_v2/api_swagger_v2_definitions-models_spec.rb +5 -4
  31. data/spec/swagger_v2/api_swagger_v2_detail_spec.rb +3 -3
  32. data/spec/swagger_v2/api_swagger_v2_extensions_spec.rb +1 -1
  33. data/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb +1 -1
  34. data/spec/swagger_v2/api_swagger_v2_headers_spec.rb +5 -3
  35. data/spec/swagger_v2/api_swagger_v2_hide_documentation_path_spec.rb +1 -1
  36. data/spec/swagger_v2/api_swagger_v2_mounted_spec.rb +1 -1
  37. data/spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb +25 -14
  38. data/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb +22 -12
  39. data/spec/swagger_v2/api_swagger_v2_param_type_spec.rb +30 -18
  40. data/spec/swagger_v2/api_swagger_v2_request_params_fix_spec.rb +6 -3
  41. data/spec/swagger_v2/api_swagger_v2_response_spec.rb +13 -40
  42. data/spec/swagger_v2/api_swagger_v2_spec.rb +4 -2
  43. data/spec/swagger_v2/api_swagger_v2_type-format_spec.rb +6 -36
  44. data/spec/swagger_v2/default_api_spec.rb +10 -2
  45. data/spec/swagger_v2/endpoint_versioned_path_spec.rb +30 -0
  46. data/spec/swagger_v2/errors_spec.rb +75 -0
  47. data/spec/swagger_v2/hide_api_spec.rb +22 -4
  48. data/spec/swagger_v2/mounted_target_class_spec.rb +6 -2
  49. data/spec/swagger_v2/namespace_tags_prefix_spec.rb +6 -3
  50. data/spec/swagger_v2/namespace_tags_spec.rb +6 -3
  51. data/spec/swagger_v2/params_array_spec.rb +4 -2
  52. data/spec/swagger_v2/params_hash_spec.rb +4 -2
  53. data/spec/swagger_v2/params_nested_spec.rb +4 -2
  54. data/spec/swagger_v2/simple_mounted_api_spec.rb +66 -24
  55. metadata +23 -40
  56. data/spec/support/the_api_entities.rb +0 -50
  57. data/spec/swagger_v2/response_model_spec.rb +0 -208
@@ -28,7 +28,8 @@ describe GrapeSwagger::DocMethods::ProducesConsumes do
28
28
  'application/json',
29
29
  'application/octet-stream',
30
30
  'text/plain'
31
- ])
31
+ ]
32
+ )
32
33
  end
33
34
  end
34
35
  end
@@ -59,7 +60,8 @@ describe GrapeSwagger::DocMethods::ProducesConsumes do
59
60
  'application/json',
60
61
  'application/octet-stream',
61
62
  'text/plain'
62
- ])
63
+ ]
64
+ )
63
65
  end
64
66
  end
65
67
  end
@@ -82,7 +84,8 @@ describe GrapeSwagger::DocMethods::ProducesConsumes do
82
84
  'application/json',
83
85
  'application/octet-stream',
84
86
  'text/plain'
85
- ])
87
+ ]
88
+ )
86
89
  end
87
90
 
88
91
  subject do
@@ -93,7 +96,8 @@ describe GrapeSwagger::DocMethods::ProducesConsumes do
93
96
  'application/json',
94
97
  'application/octet-stream',
95
98
  :txt
96
- ])
99
+ ]
100
+ )
97
101
  end
98
102
 
99
103
  specify do
@@ -103,7 +107,8 @@ describe GrapeSwagger::DocMethods::ProducesConsumes do
103
107
  'application/json',
104
108
  'application/octet-stream',
105
109
  'text/plain'
106
- ])
110
+ ]
111
+ )
107
112
  end
108
113
  end
109
114
  end
@@ -1,10 +1,12 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
2
 
3
- Dir[File.join(Dir.getwd, 'spec/support/**/*.rb')].each { |f| require f }
3
+ MODEL_PARSER = ENV.key?('MODEL_PARSER') ? ENV['MODEL_PARSER'].to_s.downcase.sub('grape-swagger-', '') : 'mock'
4
4
 
5
5
  require 'grape'
6
6
  require 'grape-swagger'
7
- require 'grape-entity'
7
+ Dir[File.join(Dir.getwd, 'spec/support/*.rb')].each { |f| require f }
8
+ require "grape-swagger/#{MODEL_PARSER}" if MODEL_PARSER != 'mock'
9
+ require File.join(Dir.getwd, "spec/support/model_parsers/#{MODEL_PARSER}_parser.rb")
8
10
 
9
11
  Bundler.setup :default, :test
10
12
 
@@ -0,0 +1,20 @@
1
+ class EmptyClass
2
+ end
3
+
4
+ module GrapeSwagger
5
+ class EmptyModelParser
6
+ attr_reader :model
7
+ attr_reader :endpoint
8
+
9
+ def initialize(model, endpoint)
10
+ @model = model
11
+ @endpoint = endpoint
12
+ end
13
+
14
+ def call
15
+ {}
16
+ end
17
+ end
18
+ end
19
+
20
+ GrapeSwagger.model_parsers.register(GrapeSwagger::EmptyModelParser, EmptyClass)
@@ -0,0 +1,22 @@
1
+ module GrapeSwagger
2
+ class MockParser
3
+ attr_reader :model
4
+ attr_reader :endpoint
5
+
6
+ def initialize(model, endpoint)
7
+ @model = model
8
+ @endpoint = endpoint
9
+ end
10
+
11
+ def call
12
+ {
13
+ mock_data: {
14
+ type: :string,
15
+ description: "it's a mock"
16
+ }
17
+ }
18
+ end
19
+ end
20
+ end
21
+
22
+ GrapeSwagger.model_parsers.register(GrapeSwagger::MockParser, OpenStruct)
@@ -0,0 +1,325 @@
1
+ RSpec.shared_context 'entity swagger example' do
2
+ before :all do
3
+ module Entities
4
+ class Something < Grape::Entity
5
+ expose :id, documentation: { type: Integer, desc: 'Identity of Something' }
6
+ expose :text, documentation: { type: String, desc: 'Content of something.' }
7
+ expose :links, documentation: { type: 'link', is_array: true }
8
+ expose :others, documentation: { type: 'text', is_array: false }
9
+ end
10
+
11
+ class EnumValues < Grape::Entity
12
+ expose :gender, documentation: { type: 'string', desc: 'Content of something.', values: %w(Male Female) }
13
+ expose :number, documentation: { type: 'integer', desc: 'Content of something.', values: [1, 2] }
14
+ end
15
+
16
+ class AliasedThing < Grape::Entity
17
+ expose :something, as: :post, using: Entities::Something, documentation: { type: 'Something', desc: 'Reference to something.' }
18
+ end
19
+
20
+ class FourthLevel < Grape::Entity
21
+ expose :text, documentation: { type: 'string' }
22
+ end
23
+
24
+ class ThirdLevel < Grape::Entity
25
+ expose :parts, using: Entities::FourthLevel, documentation: { type: 'FourthLevel' }
26
+ end
27
+
28
+ class SecondLevel < Grape::Entity
29
+ expose :parts, using: Entities::ThirdLevel, documentation: { type: 'ThirdLevel' }
30
+ end
31
+
32
+ class FirstLevel < Grape::Entity
33
+ expose :parts, using: Entities::SecondLevel, documentation: { type: 'SecondLevel' }
34
+ end
35
+
36
+ class QueryInputElement < Grape::Entity
37
+ expose :key, documentation: {
38
+ type: String, desc: 'Name of parameter', required: true
39
+ }
40
+ expose :value, documentation: {
41
+ type: String, desc: 'Value of parameter', required: true
42
+ }
43
+ end
44
+
45
+ class QueryInput < Grape::Entity
46
+ expose :elements, using: Entities::QueryInputElement, documentation: {
47
+ type: 'QueryInputElement',
48
+ desc: 'Set of configuration',
49
+ param_type: 'body',
50
+ is_array: true,
51
+ required: true
52
+ }
53
+ end
54
+
55
+ class ApiError < Grape::Entity
56
+ expose :code, documentation: { type: Integer, desc: 'status code' }
57
+ expose :message, documentation: { type: String, desc: 'error message' }
58
+ end
59
+
60
+ class SecondApiError < Grape::Entity
61
+ expose :code, documentation: { type: Integer }
62
+ expose :severity, documentation: { type: String }
63
+ expose :message, documentation: { type: String }
64
+ end
65
+
66
+ class ResponseItem < Grape::Entity
67
+ expose :id, documentation: { type: Integer }
68
+ expose :name, documentation: { type: String }
69
+ end
70
+
71
+ class OtherItem < Grape::Entity
72
+ expose :key, documentation: { type: Integer }
73
+ expose :symbol, documentation: { type: String }
74
+ end
75
+
76
+ class UseResponse < Grape::Entity
77
+ expose :description, documentation: { type: String }
78
+ expose :items, as: '$responses', using: Entities::ResponseItem, documentation: { is_array: true }
79
+ end
80
+
81
+ class UseItemResponseAsType < Grape::Entity
82
+ expose :description, documentation: { type: String }
83
+ expose :responses, documentation: { type: Entities::ResponseItem, is_array: false }
84
+ end
85
+
86
+ class UseAddress < Grape::Entity
87
+ expose :street, documentation: { type: String, desc: 'street' }
88
+ expose :postcode, documentation: { type: String, desc: 'postcode' }
89
+ expose :city, documentation: { type: String, desc: 'city' }
90
+ expose :country, documentation: { type: String, desc: 'country' }
91
+ end
92
+
93
+ class UseNestedWithAddress < Grape::Entity
94
+ expose :name, documentation: { type: String }
95
+ expose :address, using: Entities::UseAddress
96
+ end
97
+
98
+ class TypedDefinition < Grape::Entity
99
+ expose :prop_integer, documentation: { type: Integer, desc: 'prop_integer description' }
100
+ expose :prop_long, documentation: { type: Numeric, desc: 'prop_long description' }
101
+ expose :prop_float, documentation: { type: Float, desc: 'prop_float description' }
102
+ expose :prop_double, documentation: { type: BigDecimal, desc: 'prop_double description' }
103
+ expose :prop_string, documentation: { type: String, desc: 'prop_string description' }
104
+ expose :prop_symbol, documentation: { type: Symbol, desc: 'prop_symbol description' }
105
+ expose :prop_date, documentation: { type: Date, desc: 'prop_date description' }
106
+ expose :prop_date_time, documentation: { type: DateTime, desc: 'prop_date_time description' }
107
+ expose :prop_time, documentation: { type: Time, desc: 'prop_time description' }
108
+ expose :prop_password, documentation: { type: 'password', desc: 'prop_password description' }
109
+ expose :prop_email, documentation: { type: 'email', desc: 'prop_email description' }
110
+ expose :prop_boolean, documentation: { type: Virtus::Attribute::Boolean, desc: 'prop_boolean description' }
111
+ expose :prop_file, documentation: { type: File, desc: 'prop_file description' }
112
+ expose :prop_json, documentation: { type: JSON, desc: 'prop_json description' }
113
+ end
114
+
115
+ class RecursiveModel < Grape::Entity
116
+ expose :name, documentation: { type: String, desc: 'The name.' }
117
+ expose :children, using: self, documentation: { type: 'RecursiveModel', is_array: true, desc: 'The child nodes.' }
118
+ end
119
+ end
120
+ end
121
+
122
+ let(:swagger_definitions_models) do
123
+ {
124
+ 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } } },
125
+ 'ResponseItem' => { 'type' => 'object', 'properties' => { 'id' => { 'type' => 'integer', 'format' => 'int32' }, 'name' => { 'type' => 'string' } } },
126
+ 'UseResponse' => { 'type' => 'object', 'properties' => { 'description' => { 'type' => 'string' }, '$responses' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/ResponseItem' } } } },
127
+ 'RecursiveModel' => { 'type' => 'object', 'properties' => { 'name' => { 'type' => 'string', 'description' => 'The name.' }, 'children' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/RecursiveModel' }, 'description' => 'The child nodes.' } } }
128
+ }
129
+ end
130
+
131
+ let(:swagger_nested_type) do
132
+ {
133
+ 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } }, 'description' => 'This returns something' },
134
+ 'ResponseItem' => { 'type' => 'object', 'properties' => { 'id' => { 'type' => 'integer', 'format' => 'int32' }, 'name' => { 'type' => 'string' } } },
135
+ 'UseItemResponseAsType' => { 'type' => 'object', 'properties' => { 'description' => { 'type' => 'string' }, 'responses' => { '$ref' => '#/definitions/ResponseItem' } }, 'description' => 'This returns something' }
136
+ }
137
+ end
138
+
139
+ let(:swagger_entity_as_response_object) do
140
+ {
141
+ 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } }, 'description' => 'This returns something' },
142
+ 'ResponseItem' => { 'type' => 'object', 'properties' => { 'id' => { 'type' => 'integer', 'format' => 'int32' }, 'name' => { 'type' => 'string' } } },
143
+ 'UseResponse' => { 'type' => 'object', 'properties' => { 'description' => { 'type' => 'string' }, '$responses' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/ResponseItem' } } }, 'description' => 'This returns something' }
144
+ }
145
+ end
146
+
147
+ let(:swagger_params_as_response_object) do
148
+ {
149
+ 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'description' => 'status code', 'type' => 'integer', 'format' => 'int32' }, 'message' => { 'description' => 'error message', 'type' => 'string' } }, 'description' => 'This returns something' }
150
+ }
151
+ end
152
+
153
+ let(:swagger_typed_defintion) do
154
+ {
155
+ 'prop_boolean' => { 'description' => 'prop_boolean description', 'type' => 'boolean' },
156
+ 'prop_date' => { 'description' => 'prop_date description', 'type' => 'string', 'format' => 'date' },
157
+ 'prop_date_time' => { 'description' => 'prop_date_time description', 'type' => 'string', 'format' => 'date-time' },
158
+ 'prop_double' => { 'description' => 'prop_double description', 'type' => 'number', 'format' => 'double' },
159
+ 'prop_email' => { 'description' => 'prop_email description', 'type' => 'string', 'format' => 'email' },
160
+ 'prop_file' => { 'description' => 'prop_file description', 'type' => 'file' },
161
+ 'prop_float' => { 'description' => 'prop_float description', 'type' => 'number', 'format' => 'float' },
162
+ 'prop_integer' => { 'description' => 'prop_integer description', 'type' => 'integer', 'format' => 'int32' },
163
+ 'prop_json' => { 'description' => 'prop_json description', 'type' => 'json' },
164
+ 'prop_long' => { 'description' => 'prop_long description', 'type' => 'integer', 'format' => 'int64' },
165
+ 'prop_password' => { 'description' => 'prop_password description', 'type' => 'string', 'format' => 'password' },
166
+ 'prop_string' => { 'description' => 'prop_string description', 'type' => 'string' },
167
+ 'prop_symbol' => { 'description' => 'prop_symbol description', 'type' => 'string' },
168
+ 'prop_time' => { 'description' => 'prop_time description', 'type' => 'string', 'format' => 'date-time' }
169
+ }
170
+ end
171
+
172
+ let(:swagger_json) do
173
+ {
174
+ 'info' => {
175
+ 'title' => 'The API title to be displayed on the API homepage.',
176
+ 'description' => 'A description of the API.',
177
+ 'termsOfServiceUrl' => 'www.The-URL-of-the-terms-and-service.com',
178
+ 'contact' => { 'name' => 'Contact name', 'email' => 'Contact@email.com', 'url' => 'Contact URL' },
179
+ 'license' => { 'name' => 'The name of the license.', 'url' => 'www.The-URL-of-the-license.org' },
180
+ 'version' => '0.0.1'
181
+ },
182
+ 'swagger' => '2.0',
183
+ 'produces' => ['application/json'],
184
+ 'host' => 'example.org',
185
+ 'basePath' => '/api',
186
+ 'tags' => [
187
+ { 'name' => 'other_thing', 'description' => 'Operations about other_things' },
188
+ { 'name' => 'thing', 'description' => 'Operations about things' },
189
+ { 'name' => 'thing2', 'description' => 'Operations about thing2s' },
190
+ { 'name' => 'dummy', 'description' => 'Operations about dummies' }
191
+ ],
192
+ 'paths' => {
193
+ '/v3/other_thing/{elements}' => {
194
+ 'get' => {
195
+ 'summary' => 'nested route inside namespace',
196
+ 'description' => 'nested route inside namespace',
197
+ 'produces' => ['application/json'],
198
+ 'parameters' => [{ 'in' => 'body', 'name' => 'elements', 'description' => 'Set of configuration', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true }],
199
+ 'responses' => { '200' => { 'description' => 'nested route inside namespace', 'schema' => { '$ref' => '#/definitions/QueryInput' } } },
200
+ 'tags' => ['other_thing'],
201
+ 'operationId' => 'getV3OtherThingElements',
202
+ 'x-amazon-apigateway-auth' => { 'type' => 'none' },
203
+ 'x-amazon-apigateway-integration' => { 'type' => 'aws', 'uri' => 'foo_bar_uri', 'httpMethod' => 'get' }
204
+ }
205
+ },
206
+ '/thing' => {
207
+ 'get' => {
208
+ 'summary' => 'This gets Things.',
209
+ 'description' => 'This gets Things.',
210
+ 'produces' => ['application/json'],
211
+ 'parameters' => [
212
+ { 'in' => 'query', 'name' => 'id', 'description' => 'Identity of Something', 'type' => 'integer', 'format' => 'int32', 'required' => false },
213
+ { 'in' => 'query', 'name' => 'text', 'description' => 'Content of something.', 'type' => 'string', 'required' => false },
214
+ { 'in' => 'formData', 'name' => 'links', 'type' => 'array', 'items' => { 'type' => 'link' }, 'required' => false },
215
+ { 'in' => 'query', 'name' => 'others', 'type' => 'text', 'required' => false }
216
+ ],
217
+ 'responses' => { '200' => { 'description' => 'This gets Things.' }, '401' => { 'description' => 'Unauthorized', 'schema' => { '$ref' => '#/definitions/ApiError' } } },
218
+ 'tags' => ['thing'],
219
+ 'operationId' => 'getThing'
220
+ },
221
+ 'post' => {
222
+ 'summary' => 'This creates Thing.',
223
+ 'description' => 'This creates Thing.',
224
+ 'produces' => ['application/json'],
225
+ 'consumes' => ['application/json'],
226
+ 'parameters' => [
227
+ { 'in' => 'formData', 'name' => 'text', 'description' => 'Content of something.', 'type' => 'string', 'required' => true },
228
+ { 'in' => 'formData', 'name' => 'links', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true }
229
+ ],
230
+ 'responses' => { '201' => { 'description' => 'This creates Thing.', 'schema' => { '$ref' => '#/definitions/Something' } }, '422' => { 'description' => 'Unprocessible Entity' } },
231
+ 'tags' => ['thing'],
232
+ 'operationId' => 'postThing'
233
+ }
234
+ },
235
+ '/thing/{id}' => {
236
+ 'get' => {
237
+ 'summary' => 'This gets Thing.',
238
+ 'description' => 'This gets Thing.',
239
+ 'produces' => ['application/json'],
240
+ 'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
241
+ 'responses' => { '200' => { 'description' => 'getting a single thing' }, '401' => { 'description' => 'Unauthorized' } },
242
+ 'tags' => ['thing'],
243
+ 'operationId' => 'getThingId'
244
+ },
245
+ 'put' => {
246
+ 'summary' => 'This updates Thing.',
247
+ 'description' => 'This updates Thing.',
248
+ 'produces' => ['application/json'],
249
+ 'consumes' => ['application/json'],
250
+ 'parameters' => [
251
+ { 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true },
252
+ { 'in' => 'formData', 'name' => 'text', 'description' => 'Content of something.', 'type' => 'string', 'required' => false },
253
+ { 'in' => 'formData', 'name' => 'links', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => false }
254
+ ],
255
+ 'responses' => { '200' => { 'description' => 'This updates Thing.', 'schema' => { '$ref' => '#/definitions/Something' } } },
256
+ 'tags' => ['thing'],
257
+ 'operationId' => 'putThingId'
258
+ },
259
+ 'delete' => {
260
+ 'summary' => 'This deletes Thing.',
261
+ 'description' => 'This deletes Thing.',
262
+ 'produces' => ['application/json'],
263
+ 'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
264
+ 'responses' => { '200' => { 'description' => 'This deletes Thing.', 'schema' => { '$ref' => '#/definitions/Something' } } },
265
+ 'tags' => ['thing'],
266
+ 'operationId' => 'deleteThingId'
267
+ }
268
+ },
269
+ '/thing2' => {
270
+ 'get' => {
271
+ 'summary' => 'This gets Things.',
272
+ 'description' => 'This gets Things.',
273
+ 'produces' => ['application/json'],
274
+ 'responses' => { '200' => { 'description' => 'get Horses', 'schema' => { '$ref' => '#/definitions/Something' } }, '401' => { 'description' => 'HorsesOutError', 'schema' => { '$ref' => '#/definitions/ApiError' } } },
275
+ 'tags' => ['thing2'],
276
+ 'operationId' => 'getThing2'
277
+ }
278
+ },
279
+ '/dummy/{id}' => {
280
+ 'delete' => {
281
+ 'summary' => 'dummy route.',
282
+ 'description' => 'dummy route.',
283
+ 'produces' => ['application/json'],
284
+ 'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
285
+ 'responses' => { '204' => { 'description' => 'dummy route.' }, '401' => { 'description' => 'Unauthorized' } },
286
+ 'tags' => ['dummy'],
287
+ 'operationId' => 'deleteDummyId'
288
+ }
289
+ }
290
+ },
291
+ 'definitions' => {
292
+ 'QueryInput' => {
293
+ 'type' => 'object',
294
+ 'properties' => { 'elements' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/QueryInputElement' }, 'description' => 'Set of configuration' } },
295
+ 'description' => 'nested route inside namespace'
296
+ },
297
+ 'QueryInputElement' => {
298
+ 'type' => 'object',
299
+ 'properties' => { 'key' => { 'type' => 'string', 'description' => 'Name of parameter' }, 'value' => { 'type' => 'string', 'description' => 'Value of parameter' } }
300
+ },
301
+ 'ApiError' => {
302
+ 'type' => 'object',
303
+ 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } },
304
+ 'description' => 'This gets Things.'
305
+ },
306
+ 'Something' => {
307
+ 'type' => 'object',
308
+ 'properties' => {
309
+ 'id' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'Identity of Something' },
310
+ 'text' => { 'type' => 'string', 'description' => 'Content of something.' },
311
+ 'links' => { 'type' => 'link' },
312
+ 'others' => { 'type' => 'text' }
313
+ },
314
+ 'description' => 'This gets Things.'
315
+ }
316
+ }
317
+ }
318
+ end
319
+
320
+ let(:http_verbs) { %w(get post put delete) }
321
+ end
322
+
323
+ def mounted_paths
324
+ %w( /thing /other_thing /dummy )
325
+ end
@@ -1,60 +1,164 @@
1
- RSpec.shared_context 'swagger example' do
1
+ RSpec.shared_context 'mock swagger example' do
2
2
  before :all do
3
3
  module Entities
4
- class Something < Grape::Entity
5
- expose :id, documentation: { type: Integer, desc: 'Identity of Something' }
6
- expose :text, documentation: { type: String, desc: 'Content of something.' }
7
- expose :links, documentation: { type: 'link', is_array: true }
8
- expose :others, documentation: { type: 'text', is_array: false }
4
+ class Something < OpenStruct
5
+ class << self
6
+ # Representable doesn't have documentation method, mock this
7
+ def documentation
8
+ {
9
+ id: { type: Integer, desc: 'Identity of Something' },
10
+ text: { type: String, desc: 'Content of something.' },
11
+ links: { type: 'link', is_array: true },
12
+ others: { type: 'text', is_array: false }
13
+ }
14
+ end
15
+ end
9
16
  end
10
17
 
11
- class EnumValues < Grape::Entity
12
- expose :gender, documentation: { type: 'string', desc: 'Content of something.', values: %w(Male Female) }
13
- expose :number, documentation: { type: 'integer', desc: 'Content of something.', values: [1, 2] }
18
+ class UseResponse < OpenStruct
19
+ class << self
20
+ def documentation
21
+ {
22
+ :description => { type: String },
23
+ '$responses' => { is_array: true }
24
+ }
25
+ end
26
+ end
14
27
  end
15
28
 
16
- class AliasedThing < Grape::Entity
17
- expose :something, as: :post, using: Entities::Something, documentation: { type: 'Something', desc: 'Reference to something.' }
29
+ class ResponseItem < OpenStruct
30
+ class << self
31
+ def documentation
32
+ {
33
+ id: { type: Integer },
34
+ name: { type: String }
35
+ }
36
+ end
37
+ end
18
38
  end
19
39
 
20
- class FourthLevel < Grape::Entity
21
- expose :text, documentation: { type: 'string' }
22
- end
23
-
24
- class ThirdLevel < Grape::Entity
25
- expose :parts, using: Entities::FourthLevel, documentation: { type: 'FourthLevel' }
26
- end
40
+ class UseNestedWithAddress < OpenStruct; end
41
+ class TypedDefinition < OpenStruct; end
42
+ class UseItemResponseAsType < OpenStruct; end
43
+ class OtherItem < OpenStruct; end
44
+ class EnumValues < OpenStruct; end
45
+ class AliasedThing < OpenStruct; end
46
+ class FourthLevel < OpenStruct; end
47
+ class ThirdLevel < OpenStruct; end
48
+ class SecondLevel < OpenStruct; end
49
+ class FirstLevel < OpenStruct; end
50
+ class QueryInputElement < OpenStruct; end
51
+ class QueryInput < OpenStruct; end
52
+ class ApiError < OpenStruct; end
53
+ class SecondApiError < OpenStruct; end
54
+ class RecursiveModel < OpenStruct; end
55
+ end
56
+ end
27
57
 
28
- class SecondLevel < Grape::Entity
29
- expose :parts, using: Entities::ThirdLevel, documentation: { type: 'ThirdLevel' }
30
- end
58
+ let(:swagger_definitions_models) do
59
+ {
60
+ 'ApiError' => {
61
+ 'type' => 'object',
62
+ 'properties' => {
63
+ 'mock_data' => {
64
+ 'type' => 'string',
65
+ 'description' => "it's a mock"
66
+ }
67
+ }
68
+ },
69
+ 'RecursiveModel' => {
70
+ 'type' => 'object',
71
+ 'properties' => {
72
+ 'mock_data' => {
73
+ 'type' => 'string',
74
+ 'description' => "it's a mock"
75
+ }
76
+ }
77
+ },
78
+ 'UseResponse' => {
79
+ 'type' => 'object',
80
+ 'properties' => {
81
+ 'mock_data' => {
82
+ 'type' => 'string',
83
+ 'description' => "it's a mock"
84
+ }
85
+ }
86
+ }
87
+ }
88
+ end
31
89
 
32
- class FirstLevel < Grape::Entity
33
- expose :parts, using: Entities::SecondLevel, documentation: { type: 'SecondLevel' }
34
- end
90
+ let(:swagger_nested_type) do
91
+ {
92
+ 'ApiError' => {
93
+ 'type' => 'object',
94
+ 'properties' => {
95
+ 'mock_data' => {
96
+ 'type' => 'string',
97
+ 'description' => "it's a mock"
98
+ }
99
+ },
100
+ 'description' => 'This returns something'
101
+ },
102
+ 'UseItemResponseAsType' => {
103
+ 'type' => 'object',
104
+ 'properties' => {
105
+ 'mock_data' => {
106
+ 'type' => 'string',
107
+ 'description' => "it's a mock"
108
+ }
109
+ },
110
+ 'description' => 'This returns something'
111
+ }
112
+ }
113
+ end
35
114
 
36
- class QueryInputElement < Grape::Entity
37
- expose :key, documentation: {
38
- type: String, desc: 'Name of parameter', required: true }
39
- expose :value, documentation: {
40
- type: String, desc: 'Value of parameter', required: true }
41
- end
115
+ let(:swagger_entity_as_response_object) do
116
+ {
117
+ 'UseResponse' => {
118
+ 'type' => 'object',
119
+ 'properties' => {
120
+ 'mock_data' => {
121
+ 'type' => 'string',
122
+ 'description' => "it's a mock"
123
+ }
124
+ },
125
+ 'description' => 'This returns something'
126
+ },
127
+ 'ApiError' => {
128
+ 'type' => 'object',
129
+ 'properties' => {
130
+ 'mock_data' => {
131
+ 'type' => 'string',
132
+ 'description' => "it's a mock"
133
+ }
134
+ },
135
+ 'description' => 'This returns something'
136
+ }
137
+ }
138
+ end
42
139
 
43
- class QueryInput < Grape::Entity
44
- expose :elements, using: Entities::QueryInputElement, documentation: {
45
- type: 'QueryInputElement',
46
- desc: 'Set of configuration',
47
- param_type: 'body',
48
- is_array: true,
49
- required: true
50
- }
51
- end
140
+ let(:swagger_params_as_response_object) do
141
+ {
142
+ 'ApiError' => {
143
+ 'type' => 'object',
144
+ 'properties' => {
145
+ 'mock_data' => {
146
+ 'type' => 'string',
147
+ 'description' => "it's a mock"
148
+ }
149
+ },
150
+ 'description' => 'This returns something'
151
+ }
152
+ }
153
+ end
52
154
 
53
- class ApiError < Grape::Entity
54
- expose :code, documentation: { type: Integer, desc: 'status code' }
55
- expose :message, documentation: { type: String, desc: 'error message' }
56
- end
57
- end
155
+ let(:swagger_typed_defintion) do
156
+ {
157
+ 'mock_data' => {
158
+ 'type' => 'string',
159
+ 'description' => "it's a mock"
160
+ }
161
+ }
58
162
  end
59
163
 
60
164
  let(:swagger_json) do
@@ -80,6 +184,7 @@ RSpec.shared_context 'swagger example' do
80
184
  'paths' => {
81
185
  '/v3/other_thing/{elements}' => {
82
186
  'get' => {
187
+ 'summary' => 'nested route inside namespace',
83
188
  'description' => 'nested route inside namespace',
84
189
  'produces' => ['application/json'],
85
190
  'parameters' => [{ 'in' => 'body', 'name' => 'elements', 'description' => 'Set of configuration', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true }],
@@ -88,9 +193,11 @@ RSpec.shared_context 'swagger example' do
88
193
  'operationId' => 'getV3OtherThingElements',
89
194
  'x-amazon-apigateway-auth' => { 'type' => 'none' },
90
195
  'x-amazon-apigateway-integration' => { 'type' => 'aws', 'uri' => 'foo_bar_uri', 'httpMethod' => 'get' }
91
- } },
196
+ }
197
+ },
92
198
  '/thing' => {
93
199
  'get' => {
200
+ 'summary' => 'This gets Things.',
94
201
  'description' => 'This gets Things.',
95
202
  'produces' => ['application/json'],
96
203
  'parameters' => [
@@ -104,6 +211,7 @@ RSpec.shared_context 'swagger example' do
104
211
  'operationId' => 'getThing'
105
212
  },
106
213
  'post' => {
214
+ 'summary' => 'This creates Thing.',
107
215
  'description' => 'This creates Thing.',
108
216
  'produces' => ['application/json'],
109
217
  'consumes' => ['application/json'],
@@ -114,9 +222,11 @@ RSpec.shared_context 'swagger example' do
114
222
  'responses' => { '201' => { 'description' => 'This creates Thing.', 'schema' => { '$ref' => '#/definitions/Something' } }, '422' => { 'description' => 'Unprocessible Entity' } },
115
223
  'tags' => ['thing'],
116
224
  'operationId' => 'postThing'
117
- } },
225
+ }
226
+ },
118
227
  '/thing/{id}' => {
119
228
  'get' => {
229
+ 'summary' => 'This gets Thing.',
120
230
  'description' => 'This gets Thing.',
121
231
  'produces' => ['application/json'],
122
232
  'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
@@ -125,6 +235,7 @@ RSpec.shared_context 'swagger example' do
125
235
  'operationId' => 'getThingId'
126
236
  },
127
237
  'put' => {
238
+ 'summary' => 'This updates Thing.',
128
239
  'description' => 'This updates Thing.',
129
240
  'produces' => ['application/json'],
130
241
  'consumes' => ['application/json'],
@@ -138,55 +249,70 @@ RSpec.shared_context 'swagger example' do
138
249
  'operationId' => 'putThingId'
139
250
  },
140
251
  'delete' => {
252
+ 'summary' => 'This deletes Thing.',
141
253
  'description' => 'This deletes Thing.',
142
254
  'produces' => ['application/json'],
143
255
  'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
144
256
  'responses' => { '200' => { 'description' => 'This deletes Thing.', 'schema' => { '$ref' => '#/definitions/Something' } } },
145
257
  'tags' => ['thing'],
146
258
  'operationId' => 'deleteThingId'
147
- } },
259
+ }
260
+ },
148
261
  '/thing2' => {
149
262
  'get' => {
263
+ 'summary' => 'This gets Things.',
150
264
  'description' => 'This gets Things.',
151
265
  'produces' => ['application/json'],
152
266
  'responses' => { '200' => { 'description' => 'get Horses', 'schema' => { '$ref' => '#/definitions/Something' } }, '401' => { 'description' => 'HorsesOutError', 'schema' => { '$ref' => '#/definitions/ApiError' } } },
153
267
  'tags' => ['thing2'],
154
268
  'operationId' => 'getThing2'
155
- } },
269
+ }
270
+ },
156
271
  '/dummy/{id}' => {
157
272
  'delete' => {
273
+ 'summary' => 'dummy route.',
158
274
  'description' => 'dummy route.',
159
275
  'produces' => ['application/json'],
160
276
  'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
161
277
  'responses' => { '204' => { 'description' => 'dummy route.' }, '401' => { 'description' => 'Unauthorized' } },
162
278
  'tags' => ['dummy'],
163
279
  'operationId' => 'deleteDummyId'
164
- } } },
280
+ }
281
+ }
282
+ },
165
283
  'definitions' => {
166
284
  'QueryInput' => {
167
285
  'type' => 'object',
168
- 'properties' => { 'elements' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/QueryInputElement' }, 'description' => 'Set of configuration' } },
286
+ 'properties' => {
287
+ 'mock_data' => {
288
+ 'type' => 'string',
289
+ 'description' => "it's a mock"
290
+ }
291
+ },
169
292
  'description' => 'nested route inside namespace'
170
293
  },
171
- 'QueryInputElement' => {
172
- 'type' => 'object',
173
- 'properties' => { 'key' => { 'type' => 'string', 'description' => 'Name of parameter' }, 'value' => { 'type' => 'string', 'description' => 'Value of parameter' } }
174
- },
175
294
  'ApiError' => {
176
295
  'type' => 'object',
177
- 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } },
296
+ 'properties' => {
297
+ 'mock_data' => {
298
+ 'type' => 'string',
299
+ 'description' => "it's a mock"
300
+ }
301
+ },
178
302
  'description' => 'This gets Things.'
179
303
  },
180
304
  'Something' => {
181
305
  'type' => 'object',
182
306
  'properties' => {
183
- 'id' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'Identity of Something' },
184
- 'text' => { 'type' => 'string', 'description' => 'Content of something.' },
185
- 'links' => { 'type' => 'link' },
186
- 'others' => { 'type' => 'text' }
307
+ 'mock_data' => {
308
+ 'type' => 'string',
309
+ 'description' => "it's a mock"
310
+ }
187
311
  },
188
312
  'description' => 'This gets Things.'
189
- } } }
313
+ }
314
+ }
315
+ }
190
316
  end
191
317
 
192
318
  let(:http_verbs) { %w(get post put delete) }