gitlab-grape-swagger 1.5.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 (166) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.github/dependabot.yml +20 -0
  4. data/.github/workflows/ci.yml +45 -0
  5. data/.gitignore +44 -0
  6. data/.gitlab-ci.yml +19 -0
  7. data/.rspec +3 -0
  8. data/.rubocop.yml +136 -0
  9. data/.rubocop_todo.yml +60 -0
  10. data/.ruby-gemset +1 -0
  11. data/CHANGELOG.md +671 -0
  12. data/CONTRIBUTING.md +126 -0
  13. data/Dangerfile +3 -0
  14. data/Gemfile +45 -0
  15. data/Gemfile.lock +249 -0
  16. data/LICENSE.txt +20 -0
  17. data/README.md +1772 -0
  18. data/RELEASING.md +82 -0
  19. data/Rakefile +20 -0
  20. data/UPGRADING.md +201 -0
  21. data/example/api/endpoints.rb +131 -0
  22. data/example/api/entities.rb +18 -0
  23. data/example/config.ru +42 -0
  24. data/example/example_requests.postman_collection +146 -0
  25. data/example/splines.png +0 -0
  26. data/example/swagger-example.png +0 -0
  27. data/grape-swagger.gemspec +23 -0
  28. data/lib/grape-swagger/doc_methods/build_model_definition.rb +68 -0
  29. data/lib/grape-swagger/doc_methods/data_type.rb +110 -0
  30. data/lib/grape-swagger/doc_methods/extensions.rb +101 -0
  31. data/lib/grape-swagger/doc_methods/file_params.rb +17 -0
  32. data/lib/grape-swagger/doc_methods/format_data.rb +53 -0
  33. data/lib/grape-swagger/doc_methods/headers.rb +20 -0
  34. data/lib/grape-swagger/doc_methods/move_params.rb +209 -0
  35. data/lib/grape-swagger/doc_methods/operation_id.rb +32 -0
  36. data/lib/grape-swagger/doc_methods/optional_object.rb +30 -0
  37. data/lib/grape-swagger/doc_methods/parse_params.rb +190 -0
  38. data/lib/grape-swagger/doc_methods/path_string.rb +52 -0
  39. data/lib/grape-swagger/doc_methods/produces_consumes.rb +15 -0
  40. data/lib/grape-swagger/doc_methods/status_codes.rb +21 -0
  41. data/lib/grape-swagger/doc_methods/tag_name_description.rb +34 -0
  42. data/lib/grape-swagger/doc_methods/version.rb +20 -0
  43. data/lib/grape-swagger/doc_methods.rb +142 -0
  44. data/lib/grape-swagger/endpoint/params_parser.rb +76 -0
  45. data/lib/grape-swagger/endpoint.rb +476 -0
  46. data/lib/grape-swagger/errors.rb +17 -0
  47. data/lib/grape-swagger/instance.rb +7 -0
  48. data/lib/grape-swagger/model_parsers.rb +42 -0
  49. data/lib/grape-swagger/rake/oapi_tasks.rb +135 -0
  50. data/lib/grape-swagger/version.rb +5 -0
  51. data/lib/grape-swagger.rb +174 -0
  52. data/spec/issues/267_nested_namespaces.rb +55 -0
  53. data/spec/issues/403_versions_spec.rb +124 -0
  54. data/spec/issues/427_entity_as_string_spec.rb +39 -0
  55. data/spec/issues/430_entity_definitions_spec.rb +94 -0
  56. data/spec/issues/532_allow_custom_format_spec.rb +42 -0
  57. data/spec/issues/533_specify_status_code_spec.rb +78 -0
  58. data/spec/issues/537_enum_values_spec.rb +50 -0
  59. data/spec/issues/539_array_post_body_spec.rb +65 -0
  60. data/spec/issues/542_array_of_type_in_post_body_spec.rb +46 -0
  61. data/spec/issues/553_align_array_put_post_params_spec.rb +152 -0
  62. data/spec/issues/572_array_post_body_spec.rb +51 -0
  63. data/spec/issues/579_align_put_post_parameters_spec.rb +185 -0
  64. data/spec/issues/582_file_response_spec.rb +55 -0
  65. data/spec/issues/587_range_parameter_delimited_by_dash_spec.rb +26 -0
  66. data/spec/issues/605_root_route_documentation_spec.rb +23 -0
  67. data/spec/issues/650_params_array_spec.rb +65 -0
  68. data/spec/issues/677_consumes_produces_add_swagger_documentation_options_spec.rb +100 -0
  69. data/spec/issues/680_keep_204_error_schemas_spec.rb +55 -0
  70. data/spec/issues/721_set_default_parameter_location_based_on_consumes_spec.rb +62 -0
  71. data/spec/issues/751_deeply_nested_objects_spec.rb +190 -0
  72. data/spec/issues/776_multiple_presents_spec.rb +59 -0
  73. data/spec/issues/784_extensions_on_params_spec.rb +42 -0
  74. data/spec/issues/809_utf8_routes_spec.rb +55 -0
  75. data/spec/issues/832_array_hash_float_decimal_spec.rb +114 -0
  76. data/spec/issues/847_route_param_options_spec.rb +37 -0
  77. data/spec/issues/873_wildcard_segments_path_parameters_spec.rb +28 -0
  78. data/spec/issues/878_optional_path_segments_spec.rb +29 -0
  79. data/spec/issues/881_handle_file_params_spec.rb +38 -0
  80. data/spec/issues/883_query_array_parameter_spec.rb +46 -0
  81. data/spec/issues/884_dont_document_non_schema_examples_spec.rb +49 -0
  82. data/spec/issues/887_prevent_duplicate_operation_ids_spec.rb +35 -0
  83. data/spec/lib/data_type_spec.rb +111 -0
  84. data/spec/lib/endpoint/params_parser_spec.rb +124 -0
  85. data/spec/lib/endpoint_spec.rb +153 -0
  86. data/spec/lib/extensions_spec.rb +185 -0
  87. data/spec/lib/format_data_spec.rb +115 -0
  88. data/spec/lib/model_parsers_spec.rb +104 -0
  89. data/spec/lib/move_params_spec.rb +444 -0
  90. data/spec/lib/oapi_tasks_spec.rb +163 -0
  91. data/spec/lib/operation_id_spec.rb +55 -0
  92. data/spec/lib/optional_object_spec.rb +47 -0
  93. data/spec/lib/parse_params_spec.rb +68 -0
  94. data/spec/lib/path_string_spec.rb +101 -0
  95. data/spec/lib/produces_consumes_spec.rb +116 -0
  96. data/spec/lib/tag_name_description_spec.rb +80 -0
  97. data/spec/lib/version_spec.rb +28 -0
  98. data/spec/spec_helper.rb +39 -0
  99. data/spec/support/empty_model_parser.rb +23 -0
  100. data/spec/support/grape_version.rb +13 -0
  101. data/spec/support/mock_parser.rb +23 -0
  102. data/spec/support/model_parsers/entity_parser.rb +334 -0
  103. data/spec/support/model_parsers/mock_parser.rb +346 -0
  104. data/spec/support/model_parsers/representable_parser.rb +406 -0
  105. data/spec/support/namespace_tags.rb +93 -0
  106. data/spec/support/the_paths_definitions.rb +109 -0
  107. data/spec/swagger_v2/api_documentation_spec.rb +42 -0
  108. data/spec/swagger_v2/api_swagger_v2_additional_properties_spec.rb +83 -0
  109. data/spec/swagger_v2/api_swagger_v2_body_definitions_spec.rb +48 -0
  110. data/spec/swagger_v2/api_swagger_v2_definitions-models_spec.rb +36 -0
  111. data/spec/swagger_v2/api_swagger_v2_detail_spec.rb +79 -0
  112. data/spec/swagger_v2/api_swagger_v2_extensions_spec.rb +145 -0
  113. data/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb +137 -0
  114. data/spec/swagger_v2/api_swagger_v2_global_configuration_spec.rb +56 -0
  115. data/spec/swagger_v2/api_swagger_v2_hash_and_array_spec.rb +64 -0
  116. data/spec/swagger_v2/api_swagger_v2_headers_spec.rb +58 -0
  117. data/spec/swagger_v2/api_swagger_v2_hide_documentation_path_spec.rb +57 -0
  118. data/spec/swagger_v2/api_swagger_v2_hide_param_spec.rb +109 -0
  119. data/spec/swagger_v2/api_swagger_v2_ignore_defaults_spec.rb +48 -0
  120. data/spec/swagger_v2/api_swagger_v2_mounted_spec.rb +153 -0
  121. data/spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb +355 -0
  122. data/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb +217 -0
  123. data/spec/swagger_v2/api_swagger_v2_param_type_spec.rb +247 -0
  124. data/spec/swagger_v2/api_swagger_v2_request_params_fix_spec.rb +80 -0
  125. data/spec/swagger_v2/api_swagger_v2_response_spec.rb +147 -0
  126. data/spec/swagger_v2/api_swagger_v2_response_with_examples_spec.rb +135 -0
  127. data/spec/swagger_v2/api_swagger_v2_response_with_headers_spec.rb +216 -0
  128. data/spec/swagger_v2/api_swagger_v2_response_with_models_spec.rb +53 -0
  129. data/spec/swagger_v2/api_swagger_v2_response_with_root_spec.rb +153 -0
  130. data/spec/swagger_v2/api_swagger_v2_spec.rb +245 -0
  131. data/spec/swagger_v2/api_swagger_v2_status_codes_spec.rb +93 -0
  132. data/spec/swagger_v2/api_swagger_v2_type-format_spec.rb +90 -0
  133. data/spec/swagger_v2/boolean_params_spec.rb +38 -0
  134. data/spec/swagger_v2/default_api_spec.rb +175 -0
  135. data/spec/swagger_v2/deprecated_field_spec.rb +25 -0
  136. data/spec/swagger_v2/description_not_initialized_spec.rb +39 -0
  137. data/spec/swagger_v2/endpoint_versioned_path_spec.rb +130 -0
  138. data/spec/swagger_v2/errors_spec.rb +77 -0
  139. data/spec/swagger_v2/float_api_spec.rb +36 -0
  140. data/spec/swagger_v2/form_params_spec.rb +76 -0
  141. data/spec/swagger_v2/grape-swagger_spec.rb +17 -0
  142. data/spec/swagger_v2/guarded_endpoint_spec.rb +162 -0
  143. data/spec/swagger_v2/hide_api_spec.rb +147 -0
  144. data/spec/swagger_v2/host_spec.rb +43 -0
  145. data/spec/swagger_v2/inheritance_and_discriminator_spec.rb +57 -0
  146. data/spec/swagger_v2/mount_override_api_spec.rb +58 -0
  147. data/spec/swagger_v2/mounted_target_class_spec.rb +76 -0
  148. data/spec/swagger_v2/namespace_tags_prefix_spec.rb +122 -0
  149. data/spec/swagger_v2/namespace_tags_spec.rb +78 -0
  150. data/spec/swagger_v2/namespaced_api_spec.rb +121 -0
  151. data/spec/swagger_v2/nicknamed_api_spec.rb +25 -0
  152. data/spec/swagger_v2/operation_id_api_spec.rb +27 -0
  153. data/spec/swagger_v2/param_multi_type_spec.rb +82 -0
  154. data/spec/swagger_v2/param_type_spec.rb +95 -0
  155. data/spec/swagger_v2/param_values_spec.rb +180 -0
  156. data/spec/swagger_v2/params_array_collection_format_spec.rb +105 -0
  157. data/spec/swagger_v2/params_array_spec.rb +225 -0
  158. data/spec/swagger_v2/params_example_spec.rb +38 -0
  159. data/spec/swagger_v2/params_hash_spec.rb +77 -0
  160. data/spec/swagger_v2/params_nested_spec.rb +92 -0
  161. data/spec/swagger_v2/parent_less_namespace_spec.rb +32 -0
  162. data/spec/swagger_v2/reference_entity_spec.rb +129 -0
  163. data/spec/swagger_v2/security_requirement_spec.rb +46 -0
  164. data/spec/swagger_v2/simple_mounted_api_spec.rb +332 -0
  165. data/spec/version_spec.rb +10 -0
  166. metadata +225 -0
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'response with headers' do
6
+ # include_context "#{MODEL_PARSER} swagger header"
7
+
8
+ before :all do
9
+ module TheApi
10
+ class ResponseApiHeaders < Grape::API
11
+ format :json
12
+
13
+ desc 'This returns headers' do
14
+ success model: Entities::UseResponse, headers: { 'Location' => { description: 'Location of resource', type: 'string' } }
15
+ failure [[404, 'NotFound', Entities::ApiError, { 'application/json' => { code: 404, message: 'Not found' } }, { 'Date' => { description: 'Date of failure', type: 'string' } }]]
16
+ end
17
+ get '/response_headers' do
18
+ { 'declared_params' => declared(params) }
19
+ end
20
+
21
+ desc 'A 204 can have headers too' do
22
+ foo = { status: 204, message: 'No content', headers: { 'Location' => { description: 'Location of resource', type: 'string' } } }
23
+ success foo
24
+ failure [[400, 'Bad Request', Entities::ApiError, { 'application/json' => { code: 400, message: 'Bad request' } }, { 'Date' => { description: 'Date of failure', type: 'string' } }]]
25
+ end
26
+ delete '/no_content_response_headers' do
27
+ { 'declared_params' => declared(params) }
28
+ end
29
+
30
+ desc 'A file can have headers too' do
31
+ foo = { status: 200, model: 'File', headers: { 'Cache-Control': { description: 'Directive for caching', type: 'string' } } }
32
+ success foo
33
+ failure [[404, 'NotFound', Entities::ApiError, { 'application/json' => { code: 404, message: 'Not found' } }, { 'Date' => { description: 'Date of failure', type: 'string' } }]]
34
+ end
35
+ get '/file_response_headers' do
36
+ { 'declared_params' => declared(params) }
37
+ end
38
+
39
+ desc 'This syntax also returns headers' do
40
+ success model: Entities::UseResponse, headers: { 'Location' => { description: 'Location of resource', type: 'string' } }
41
+ failure [
42
+ {
43
+ code: 404,
44
+ message: 'NotFound',
45
+ model: Entities::ApiError,
46
+ headers: { 'Date' => { description: 'Date of failure', type: 'string' } }
47
+ },
48
+ {
49
+ code: 400,
50
+ message: 'BadRequest',
51
+ model: Entities::ApiError,
52
+ headers: { 'Date' => { description: 'Date of failure', type: 'string' } }
53
+ }
54
+ ]
55
+ end
56
+ get '/response_failure_headers' do
57
+ { 'declared_params' => declared(params) }
58
+ end
59
+
60
+ desc 'This does not return headers' do
61
+ success model: Entities::UseResponse
62
+ failure [[404, 'NotFound', Entities::ApiError]]
63
+ end
64
+ get '/response_no_headers' do
65
+ { 'declared_params' => declared(params) }
66
+ end
67
+ add_swagger_documentation
68
+ end
69
+ end
70
+ end
71
+
72
+ def app
73
+ TheApi::ResponseApiHeaders
74
+ end
75
+
76
+ describe 'response headers' do
77
+ let(:header_200) do
78
+ { 'Location' => { 'description' => 'Location of resource', 'type' => 'string' } }
79
+ end
80
+ let(:header_404) do
81
+ { 'Date' => { 'description' => 'Date of failure', 'type' => 'string' } }
82
+ end
83
+ let(:examples_404) do
84
+ { 'application/json' => { 'code' => 404, 'message' => 'Not found' } }
85
+ end
86
+
87
+ subject do
88
+ get '/swagger_doc/response_headers'
89
+ JSON.parse(last_response.body)
90
+ end
91
+
92
+ specify do
93
+ expect(subject['paths']['/response_headers']['get']).to eql(
94
+ 'description' => 'This returns headers',
95
+ 'produces' => ['application/json'],
96
+ 'responses' => {
97
+ '200' => { 'description' => 'This returns headers', 'schema' => { '$ref' => '#/definitions/UseResponse' }, 'headers' => header_200 },
98
+ '404' => { 'description' => 'NotFound', 'schema' => { '$ref' => '#/definitions/ApiError' }, 'examples' => examples_404, 'headers' => header_404 }
99
+ },
100
+ 'tags' => ['response_headers'],
101
+ 'operationId' => 'getResponseHeaders'
102
+ )
103
+ end
104
+ end
105
+
106
+ describe 'no content response headers' do
107
+ let(:header_204) do
108
+ { 'Location' => { 'description' => 'Location of resource', 'type' => 'string' } }
109
+ end
110
+ let(:header_400) do
111
+ { 'Date' => { 'description' => 'Date of failure', 'type' => 'string' } }
112
+ end
113
+ let(:examples_400) do
114
+ { 'application/json' => { 'code' => 400, 'message' => 'Bad request' } }
115
+ end
116
+
117
+ subject do
118
+ get '/swagger_doc/no_content_response_headers', {}
119
+ JSON.parse(last_response.body)
120
+ end
121
+
122
+ specify do
123
+ expect(subject['paths']['/no_content_response_headers']['delete']).to eql(
124
+ 'description' => 'A 204 can have headers too',
125
+ 'produces' => ['application/json'],
126
+ 'responses' => {
127
+ '204' => { 'description' => 'No content', 'headers' => header_204 },
128
+ '400' => { 'description' => 'Bad Request', 'headers' => header_400, 'schema' => { '$ref' => '#/definitions/ApiError' }, 'examples' => examples_400 }
129
+ },
130
+ 'tags' => ['no_content_response_headers'],
131
+ 'operationId' => 'deleteNoContentResponseHeaders'
132
+ )
133
+ end
134
+ end
135
+
136
+ describe 'file response headers' do
137
+ let(:header_200) do
138
+ { 'Cache-Control' => { 'description' => 'Directive for caching', 'type' => 'string' } }
139
+ end
140
+ let(:header_404) do
141
+ { 'Date' => { 'description' => 'Date of failure', 'type' => 'string' } }
142
+ end
143
+ let(:examples_404) do
144
+ { 'application/json' => { 'code' => 404, 'message' => 'Not found' } }
145
+ end
146
+
147
+ subject do
148
+ get '/swagger_doc/file_response_headers'
149
+ JSON.parse(last_response.body)
150
+ end
151
+
152
+ specify do
153
+ expect(subject['paths']['/file_response_headers']['get']).to eql(
154
+ 'description' => 'A file can have headers too',
155
+ 'produces' => ['application/json'],
156
+ 'responses' => {
157
+ '200' => { 'description' => 'A file can have headers too', 'headers' => header_200, 'schema' => { 'type' => 'file' } },
158
+ '404' => { 'description' => 'NotFound', 'headers' => header_404, 'schema' => { '$ref' => '#/definitions/ApiError' }, 'examples' => examples_404 }
159
+ },
160
+ 'tags' => ['file_response_headers'],
161
+ 'operationId' => 'getFileResponseHeaders'
162
+ )
163
+ end
164
+ end
165
+
166
+ describe 'response failure headers' do
167
+ let(:header_200) do
168
+ { 'Location' => { 'description' => 'Location of resource', 'type' => 'string' } }
169
+ end
170
+ let(:header_404) do
171
+ { 'Date' => { 'description' => 'Date of failure', 'type' => 'string' } }
172
+ end
173
+ let(:header_400) do
174
+ { 'Date' => { 'description' => 'Date of failure', 'type' => 'string' } }
175
+ end
176
+
177
+ subject do
178
+ get '/swagger_doc/response_failure_headers'
179
+ JSON.parse(last_response.body)
180
+ end
181
+
182
+ specify do
183
+ expect(subject['paths']['/response_failure_headers']['get']).to eql(
184
+ 'description' => 'This syntax also returns headers',
185
+ 'produces' => ['application/json'],
186
+ 'responses' => {
187
+ '200' => { 'description' => 'This syntax also returns headers', 'schema' => { '$ref' => '#/definitions/UseResponse' }, 'headers' => header_200 },
188
+ '404' => { 'description' => 'NotFound', 'schema' => { '$ref' => '#/definitions/ApiError' }, 'headers' => header_404 },
189
+ '400' => { 'description' => 'BadRequest', 'schema' => { '$ref' => '#/definitions/ApiError' }, 'headers' => header_400 }
190
+ },
191
+ 'tags' => ['response_failure_headers'],
192
+ 'operationId' => 'getResponseFailureHeaders'
193
+ )
194
+ end
195
+ end
196
+
197
+ describe 'response no headers' do
198
+ subject do
199
+ get '/swagger_doc/response_no_headers'
200
+ JSON.parse(last_response.body)
201
+ end
202
+
203
+ specify do
204
+ expect(subject['paths']['/response_no_headers']['get']).to eql(
205
+ 'description' => 'This does not return headers',
206
+ 'produces' => ['application/json'],
207
+ 'responses' => {
208
+ '200' => { 'description' => 'This does not return headers', 'schema' => { '$ref' => '#/definitions/UseResponse' } },
209
+ '404' => { 'description' => 'NotFound', 'schema' => { '$ref' => '#/definitions/ApiError' } }
210
+ },
211
+ 'tags' => ['response_no_headers'],
212
+ 'operationId' => 'getResponseNoHeaders'
213
+ )
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'response' do
6
+ include_context "#{MODEL_PARSER} swagger example"
7
+
8
+ before :all do
9
+ module TheApi
10
+ class ResponseApiModels < Grape::API
11
+ format :json
12
+
13
+ desc 'This returns something',
14
+ success: [{ code: 200 }],
15
+ failure: [
16
+ { code: 400, message: 'NotFound', model: '' },
17
+ { code: 404, message: 'BadRequest', model: Entities::ApiError }
18
+ ]
19
+ get '/use-response' do
20
+ { 'declared_params' => declared(params) }
21
+ end
22
+
23
+ add_swagger_documentation(models: [Entities::UseResponse])
24
+ end
25
+ end
26
+ end
27
+
28
+ def app
29
+ TheApi::ResponseApiModels
30
+ end
31
+
32
+ describe 'uses entity as response object implicitly with route name' do
33
+ subject do
34
+ get '/swagger_doc/use-response'
35
+ JSON.parse(last_response.body)
36
+ end
37
+
38
+ specify do
39
+ expect(subject['paths']['/use-response']['get']).to eql(
40
+ 'description' => 'This returns something',
41
+ 'produces' => ['application/json'],
42
+ 'responses' => {
43
+ '200' => { 'description' => 'This returns something', 'schema' => { '$ref' => '#/definitions/UseResponse' } },
44
+ '400' => { 'description' => 'NotFound' },
45
+ '404' => { 'description' => 'BadRequest', 'schema' => { '$ref' => '#/definitions/ApiError' } }
46
+ },
47
+ 'tags' => ['use-response'],
48
+ 'operationId' => 'getUseResponse'
49
+ )
50
+ expect(subject['definitions']).to eql(swagger_entity_as_response_object)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'response with root' do
6
+ include_context "#{MODEL_PARSER} swagger example"
7
+
8
+ before :all do
9
+ module TheApi
10
+ class ResponseApiWithRoot < Grape::API
11
+ format :json
12
+
13
+ desc 'This returns something',
14
+ http_codes: [{ code: 200, model: Entities::Something }]
15
+ get '/ordinary_response' do
16
+ { 'declared_params' => declared(params) }
17
+ end
18
+
19
+ desc 'This returns something',
20
+ is_array: true,
21
+ http_codes: [{ code: 200, model: Entities::Something }]
22
+ get '/response_with_array' do
23
+ { 'declared_params' => declared(params) }
24
+ end
25
+
26
+ route_setting :swagger, root: true
27
+ desc 'This returns something',
28
+ http_codes: [{ code: 200, model: Entities::Something }]
29
+ get '/response_with_root' do
30
+ { 'declared_params' => declared(params) }
31
+ end
32
+
33
+ route_setting :swagger, root: true
34
+ desc 'This returns underscored root',
35
+ http_codes: [{ code: 200, model: Entities::ApiError }]
36
+ get '/response_with_root_underscore' do
37
+ { 'declared_params' => declared(params) }
38
+ end
39
+
40
+ route_setting :swagger, root: true
41
+ desc 'This returns something',
42
+ is_array: true,
43
+ http_codes: [{ code: 200, model: Entities::Something }]
44
+ get '/response_with_array_and_root' do
45
+ { 'declared_params' => declared(params) }
46
+ end
47
+
48
+ route_setting :swagger, root: 'custom_root'
49
+ desc 'This returns something',
50
+ http_codes: [{ code: 200, model: Entities::Something }]
51
+ get '/response_with_custom_root' do
52
+ { 'declared_params' => declared(params) }
53
+ end
54
+
55
+ add_swagger_documentation
56
+ end
57
+ end
58
+ end
59
+
60
+ def app
61
+ TheApi::ResponseApiWithRoot
62
+ end
63
+
64
+ describe 'GET /ordinary_response' do
65
+ subject do
66
+ get '/swagger_doc/ordinary_response'
67
+ JSON.parse(last_response.body)
68
+ end
69
+
70
+ it 'does not add root or array' do
71
+ schema = subject.dig('paths', '/ordinary_response', 'get', 'responses', '200', 'schema')
72
+ expect(schema).to eq(
73
+ '$ref' => '#/definitions/Something'
74
+ )
75
+ end
76
+ end
77
+
78
+ describe 'GET /response_with_array' do
79
+ subject do
80
+ get '/swagger_doc/response_with_array'
81
+ JSON.parse(last_response.body)
82
+ end
83
+
84
+ it 'adds array to the response' do
85
+ schema = subject.dig('paths', '/response_with_array', 'get', 'responses', '200', 'schema')
86
+ expect(schema).to eq(
87
+ 'type' => 'array', 'items' => { '$ref' => '#/definitions/Something' }
88
+ )
89
+ end
90
+ end
91
+
92
+ describe 'GET /response_with_root' do
93
+ subject do
94
+ get '/swagger_doc/response_with_root'
95
+ JSON.parse(last_response.body)
96
+ end
97
+
98
+ it 'adds root to the response' do
99
+ schema = subject.dig('paths', '/response_with_root', 'get', 'responses', '200', 'schema')
100
+ expect(schema).to eq(
101
+ 'type' => 'object',
102
+ 'properties' => { 'something' => { '$ref' => '#/definitions/Something' } }
103
+ )
104
+ end
105
+ end
106
+
107
+ describe 'GET /response_with_root_underscore' do
108
+ subject do
109
+ get '/swagger_doc/response_with_root_underscore'
110
+ JSON.parse(last_response.body)
111
+ end
112
+
113
+ it 'adds root to the response' do
114
+ schema = subject.dig('paths', '/response_with_root_underscore', 'get', 'responses', '200', 'schema')
115
+ expect(schema).to eq(
116
+ 'type' => 'object',
117
+ 'properties' => { 'api_error' => { '$ref' => '#/definitions/ApiError' } }
118
+ )
119
+ end
120
+ end
121
+
122
+ describe 'GET /response_with_array_and_root' do
123
+ subject do
124
+ get '/swagger_doc/response_with_array_and_root'
125
+ JSON.parse(last_response.body)
126
+ end
127
+
128
+ it 'adds root and array to the response' do
129
+ schema = subject.dig('paths', '/response_with_array_and_root', 'get', 'responses', '200', 'schema')
130
+ expect(schema).to eq(
131
+ 'type' => 'object',
132
+ 'properties' => {
133
+ 'somethings' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/Something' } }
134
+ }
135
+ )
136
+ end
137
+ end
138
+
139
+ describe 'GET /response_with_custom_root' do
140
+ subject do
141
+ get '/swagger_doc/response_with_custom_root'
142
+ JSON.parse(last_response.body)
143
+ end
144
+
145
+ it 'adds root to the response' do
146
+ schema = subject.dig('paths', '/response_with_custom_root', 'get', 'responses', '200', 'schema')
147
+ expect(schema).to eq(
148
+ 'type' => 'object',
149
+ 'properties' => { 'custom_root' => { '$ref' => '#/definitions/Something' } }
150
+ )
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,245 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'swagger spec v2.0' do
6
+ include_context "#{MODEL_PARSER} swagger example"
7
+
8
+ def app
9
+ Class.new(Grape::API) do
10
+ format :json
11
+
12
+ # Thing stuff
13
+ desc 'This gets Things.' do
14
+ consumes ['application/x-www-form-urlencoded']
15
+ params Entities::Something.documentation
16
+ http_codes [{ code: 401, message: 'Unauthorized', model: Entities::ApiError }]
17
+ end
18
+ get '/thing' do
19
+ something = OpenStruct.new text: 'something'
20
+ present something, with: Entities::Something
21
+ end
22
+
23
+ desc 'This gets Things.' do
24
+ consumes ['application/x-www-form-urlencoded']
25
+ http_codes [
26
+ { code: 200, message: 'get Horses', model: Entities::Something },
27
+ { code: 401, message: 'HorsesOutError', model: Entities::ApiError }
28
+ ]
29
+ end
30
+ get '/thing2' do
31
+ something = OpenStruct.new text: 'something'
32
+ present something, with: Entities::Something
33
+ end
34
+
35
+ desc 'This gets Thing.' do
36
+ consumes ['application/x-www-form-urlencoded']
37
+ http_codes [{ code: 200, message: 'getting a single thing' }, { code: 401, message: 'Unauthorized' }]
38
+ end
39
+ params do
40
+ requires :id, type: Integer
41
+ end
42
+ get '/thing/:id' do
43
+ something = OpenStruct.new text: 'something'
44
+ present something, with: Entities::Something
45
+ end
46
+
47
+ desc 'This creates Thing.',
48
+ consumes: ['application/x-www-form-urlencoded'],
49
+ success: Entities::Something
50
+ params do
51
+ requires :text, type: String, documentation: { type: 'string', desc: 'Content of something.' }
52
+ requires :links, type: Array, documentation: { type: 'link', is_array: true }
53
+ end
54
+ post '/thing', http_codes: [{ code: 422, message: 'Unprocessible Entity' }] do
55
+ something = OpenStruct.new text: 'something'
56
+ present something, with: Entities::Something
57
+ end
58
+
59
+ desc 'This updates Thing.',
60
+ consumes: ['application/x-www-form-urlencoded'],
61
+ success: Entities::Something
62
+ params do
63
+ requires :id, type: Integer
64
+ optional :text, type: String, desc: 'Content of something.'
65
+ optional :links, type: Array, documentation: { type: 'link', is_array: true }
66
+ end
67
+ put '/thing/:id' do
68
+ something = OpenStruct.new text: 'something'
69
+ present something, with: Entities::Something
70
+ end
71
+
72
+ desc 'This deletes Thing.',
73
+ consumes: ['application/x-www-form-urlencoded'],
74
+ entity: Entities::Something
75
+ params do
76
+ requires :id, type: Integer
77
+ end
78
+ delete '/thing/:id' do
79
+ something = OpenStruct.new text: 'something'
80
+ present something, with: Entities::Something
81
+ end
82
+
83
+ desc 'dummy route.',
84
+ consumes: ['application/x-www-form-urlencoded'],
85
+ failure: [{ code: 401, message: 'Unauthorized' }]
86
+ params do
87
+ requires :id, type: Integer
88
+ end
89
+ delete '/dummy/:id' do
90
+ {}
91
+ end
92
+
93
+ namespace :other_thing do
94
+ desc 'nested route inside namespace',
95
+ consumes: ['application/x-www-form-urlencoded'],
96
+ entity: Entities::QueryInput,
97
+ x: {
98
+ 'amazon-apigateway-auth' => { type: 'none' },
99
+ 'amazon-apigateway-integration' => { type: 'aws', uri: 'foo_bar_uri', httpMethod: 'get' }
100
+ }
101
+
102
+ params do
103
+ requires :elements, documentation: {
104
+ type: 'QueryInputElement',
105
+ desc: 'Set of configuration',
106
+ param_type: 'body',
107
+ is_array: true,
108
+ required: true
109
+ }
110
+ end
111
+ get '/:elements' do
112
+ present something, with: Entities::QueryInput
113
+ end
114
+ end
115
+
116
+ version 'v3', using: :path
117
+ add_swagger_documentation api_version: 'v1',
118
+ base_path: '/api',
119
+ info: {
120
+ title: 'The API title to be displayed on the API homepage.',
121
+ description: 'A description of the API.',
122
+ contact_name: 'Contact name',
123
+ contact_email: 'Contact@email.com',
124
+ contact_url: 'Contact URL',
125
+ license: 'The name of the license.',
126
+ license_url: 'www.The-URL-of-the-license.org',
127
+ terms_of_service_url: 'www.The-URL-of-the-terms-and-service.com'
128
+ }
129
+ end
130
+ end
131
+
132
+ describe 'whole documentation' do
133
+ subject do
134
+ get '/v3/swagger_doc'
135
+ JSON.parse(last_response.body)
136
+ end
137
+
138
+ describe 'swagger object' do
139
+ describe 'required keys' do
140
+ it { expect(subject.keys).to include 'swagger' }
141
+ it { expect(subject['swagger']).to eql '2.0' }
142
+ it { expect(subject.keys).to include 'info' }
143
+ it { expect(subject['info']).to be_a Hash }
144
+ it { expect(subject.keys).to include 'paths' }
145
+ it { expect(subject['paths']).to be_a Hash }
146
+ end
147
+
148
+ describe 'info object required keys' do
149
+ let(:info) { subject['info'] }
150
+
151
+ it { expect(info.keys).to include 'title' }
152
+ it { expect(info['title']).to be_a String }
153
+ it { expect(info.keys).to include 'version' }
154
+ it { expect(info['version']).to be_a String }
155
+
156
+ describe 'license object' do
157
+ let(:license) { subject['info']['license'] }
158
+
159
+ it { expect(license.keys).to include 'name' }
160
+ it { expect(license['name']).to be_a String }
161
+ it { expect(license.keys).to include 'url' }
162
+ it { expect(license['url']).to be_a String }
163
+ end
164
+
165
+ describe 'contact object' do
166
+ let(:contact) { subject['info']['contact'] }
167
+
168
+ it { expect(contact.keys).to include 'name' }
169
+ it { expect(contact['name']).to be_a String }
170
+ it { expect(contact.keys).to include 'email' }
171
+ it { expect(contact['email']).to be_a String }
172
+ it { expect(contact.keys).to include 'url' }
173
+ it { expect(contact['url']).to be_a String }
174
+ end
175
+
176
+ describe 'global tags' do
177
+ let(:tags) { subject['tags'] }
178
+
179
+ it { expect(tags).to be_a Array }
180
+ it { expect(tags).not_to be_empty }
181
+ end
182
+ end
183
+
184
+ describe 'path object' do
185
+ let(:paths) { subject['paths'] }
186
+
187
+ it 'hides documentation paths per default' do
188
+ expect(paths.keys).not_to include '/swagger_doc', '/swagger_doc/{name}'
189
+ end
190
+
191
+ specify do
192
+ paths.each_pair do |path, value|
193
+ expect(path).to start_with('/')
194
+ expect(value).to be_a Hash
195
+ expect(value).not_to be_empty
196
+
197
+ value.each do |method, declaration|
198
+ expect(http_verbs).to include method
199
+ expect(declaration).to have_key('responses')
200
+
201
+ declaration['responses'].each do |status_code, response|
202
+ expect(status_code).to match(/\d{3}/)
203
+ expect(response).to have_key('description')
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ describe 'definitions object' do
211
+ let(:definitions) { subject['definitions'] }
212
+
213
+ specify do
214
+ definitions.each do |model, properties|
215
+ expect(model).to match(/\w+/)
216
+ expect(properties).to have_key('properties')
217
+ end
218
+ end
219
+ end
220
+ end
221
+
222
+ describe 'swagger file' do
223
+ it do
224
+ expect(subject).to eql swagger_json
225
+ end
226
+ end
227
+ end
228
+
229
+ describe 'specific resource documentation' do
230
+ subject do
231
+ get '/v3/swagger_doc/other_thing'
232
+ JSON.parse(last_response.body)
233
+ end
234
+
235
+ let(:tags) { subject['tags'] }
236
+ specify do
237
+ expect(tags).to eql [
238
+ {
239
+ 'name' => 'other_thing',
240
+ 'description' => 'Operations about other_things'
241
+ }
242
+ ]
243
+ end
244
+ end
245
+ end