apipie-rails-jq 1.4.3.pre.beta.pre.jq.1

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 (258) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/build.yml +32 -0
  3. data/.github/workflows/rubocop-challenger.yml +26 -0
  4. data/.github/workflows/rubocop.yml +18 -0
  5. data/.gitignore +16 -0
  6. data/.rspec +2 -0
  7. data/.rubocop.yml +132 -0
  8. data/.rubocop_todo.yml +1967 -0
  9. data/.vscode/settings.json +3 -0
  10. data/APACHE-LICENSE-2.0 +202 -0
  11. data/CHANGELOG.md +693 -0
  12. data/Gemfile +19 -0
  13. data/MIT-LICENSE +20 -0
  14. data/NOTICE +4 -0
  15. data/PROPOSAL_FOR_RESPONSE_DESCRIPTIONS.md +244 -0
  16. data/README.md +2088 -0
  17. data/Rakefile +8 -0
  18. data/apipie-rails.gemspec +44 -0
  19. data/app/controllers/apipie/apipies_controller.rb +184 -0
  20. data/app/helpers/apipie_helper.rb +10 -0
  21. data/app/public/apipie/javascripts/apipie.js +6 -0
  22. data/app/public/apipie/javascripts/bundled/bootstrap-collapse.js +167 -0
  23. data/app/public/apipie/javascripts/bundled/bootstrap.js +2280 -0
  24. data/app/public/apipie/javascripts/bundled/jquery.js +2 -0
  25. data/app/public/apipie/javascripts/bundled/prettify.js +28 -0
  26. data/app/public/apipie/stylesheets/application.css +7 -0
  27. data/app/public/apipie/stylesheets/bundled/bootstrap-responsive.min.css +9 -0
  28. data/app/public/apipie/stylesheets/bundled/bootstrap.min.css +9 -0
  29. data/app/public/apipie/stylesheets/bundled/prettify.css +30 -0
  30. data/app/views/apipie/apipies/_deprecation.html.erb +16 -0
  31. data/app/views/apipie/apipies/_disqus.html.erb +13 -0
  32. data/app/views/apipie/apipies/_errors.html.erb +23 -0
  33. data/app/views/apipie/apipies/_headers.html.erb +26 -0
  34. data/app/views/apipie/apipies/_languages.erb +6 -0
  35. data/app/views/apipie/apipies/_metadata.erb +1 -0
  36. data/app/views/apipie/apipies/_method_detail.erb +63 -0
  37. data/app/views/apipie/apipies/_params.html.erb +49 -0
  38. data/app/views/apipie/apipies/_params_plain.html.erb +21 -0
  39. data/app/views/apipie/apipies/apipie_404.html.erb +17 -0
  40. data/app/views/apipie/apipies/apipie_checksum.json.erb +1 -0
  41. data/app/views/apipie/apipies/getting_started.html.erb +6 -0
  42. data/app/views/apipie/apipies/index.html.erb +56 -0
  43. data/app/views/apipie/apipies/method.html.erb +41 -0
  44. data/app/views/apipie/apipies/plain.html.erb +77 -0
  45. data/app/views/apipie/apipies/resource.html.erb +80 -0
  46. data/app/views/apipie/apipies/static.html.erb +103 -0
  47. data/app/views/layouts/apipie/apipie.html.erb +27 -0
  48. data/config/locales/de.yml +28 -0
  49. data/config/locales/en.yml +41 -0
  50. data/config/locales/es.yml +28 -0
  51. data/config/locales/fr.yml +31 -0
  52. data/config/locales/it.yml +41 -0
  53. data/config/locales/ja.yml +31 -0
  54. data/config/locales/ko.yml +32 -0
  55. data/config/locales/pl.yml +28 -0
  56. data/config/locales/pt-BR.yml +28 -0
  57. data/config/locales/ru.yml +28 -0
  58. data/config/locales/tr.yml +28 -0
  59. data/config/locales/zh-CN.yml +28 -0
  60. data/config/locales/zh-TW.yml +28 -0
  61. data/gemfiles/Gemfile.tools +9 -0
  62. data/images/screenshot-1.png +0 -0
  63. data/images/screenshot-2.png +0 -0
  64. data/lib/apipie/apipie_module.rb +83 -0
  65. data/lib/apipie/application.rb +499 -0
  66. data/lib/apipie/configuration.rb +196 -0
  67. data/lib/apipie/core_ext/route.rb +9 -0
  68. data/lib/apipie/dsl_definition.rb +630 -0
  69. data/lib/apipie/error_description.rb +46 -0
  70. data/lib/apipie/errors.rb +86 -0
  71. data/lib/apipie/extractor/collector.rb +116 -0
  72. data/lib/apipie/extractor/recorder.rb +193 -0
  73. data/lib/apipie/extractor/writer.rb +454 -0
  74. data/lib/apipie/extractor.rb +181 -0
  75. data/lib/apipie/generator/config.rb +12 -0
  76. data/lib/apipie/generator/generator.rb +2 -0
  77. data/lib/apipie/generator/swagger/computed_interface_id.rb +23 -0
  78. data/lib/apipie/generator/swagger/config.rb +80 -0
  79. data/lib/apipie/generator/swagger/context.rb +38 -0
  80. data/lib/apipie/generator/swagger/method_description/api_decorator.rb +20 -0
  81. data/lib/apipie/generator/swagger/method_description/api_schema_service.rb +89 -0
  82. data/lib/apipie/generator/swagger/method_description/decorator.rb +22 -0
  83. data/lib/apipie/generator/swagger/method_description/parameters_service.rb +139 -0
  84. data/lib/apipie/generator/swagger/method_description/response_schema_service.rb +46 -0
  85. data/lib/apipie/generator/swagger/method_description/response_service.rb +71 -0
  86. data/lib/apipie/generator/swagger/method_description.rb +2 -0
  87. data/lib/apipie/generator/swagger/operation_id.rb +51 -0
  88. data/lib/apipie/generator/swagger/param_description/builder.rb +114 -0
  89. data/lib/apipie/generator/swagger/param_description/composite.rb +119 -0
  90. data/lib/apipie/generator/swagger/param_description/description.rb +15 -0
  91. data/lib/apipie/generator/swagger/param_description/in.rb +37 -0
  92. data/lib/apipie/generator/swagger/param_description/name.rb +18 -0
  93. data/lib/apipie/generator/swagger/param_description/path_params_composite.rb +61 -0
  94. data/lib/apipie/generator/swagger/param_description/referenced_composite.rb +36 -0
  95. data/lib/apipie/generator/swagger/param_description/type.rb +132 -0
  96. data/lib/apipie/generator/swagger/param_description.rb +18 -0
  97. data/lib/apipie/generator/swagger/path_decorator.rb +36 -0
  98. data/lib/apipie/generator/swagger/referenced_definitions.rb +17 -0
  99. data/lib/apipie/generator/swagger/resource_description_collection.rb +30 -0
  100. data/lib/apipie/generator/swagger/resource_description_composite.rb +56 -0
  101. data/lib/apipie/generator/swagger/schema.rb +63 -0
  102. data/lib/apipie/generator/swagger/swagger.rb +2 -0
  103. data/lib/apipie/generator/swagger/type.rb +16 -0
  104. data/lib/apipie/generator/swagger/type_extractor.rb +51 -0
  105. data/lib/apipie/generator/swagger/warning.rb +74 -0
  106. data/lib/apipie/generator/swagger/warning_writer.rb +54 -0
  107. data/lib/apipie/helpers.rb +73 -0
  108. data/lib/apipie/markup.rb +52 -0
  109. data/lib/apipie/method_description/api.rb +12 -0
  110. data/lib/apipie/method_description/apis_service.rb +82 -0
  111. data/lib/apipie/method_description.rb +230 -0
  112. data/lib/apipie/middleware/checksum_in_headers.rb +35 -0
  113. data/lib/apipie/param_description/deprecation.rb +24 -0
  114. data/lib/apipie/param_description.rb +313 -0
  115. data/lib/apipie/railtie.rb +9 -0
  116. data/lib/apipie/resource_description.rb +152 -0
  117. data/lib/apipie/response_description.rb +157 -0
  118. data/lib/apipie/response_description_adapter.rb +202 -0
  119. data/lib/apipie/routes_formatter.rb +33 -0
  120. data/lib/apipie/routing.rb +16 -0
  121. data/lib/apipie/rspec/response_validation_helper.rb +194 -0
  122. data/lib/apipie/see_description.rb +39 -0
  123. data/lib/apipie/static_dispatcher.rb +75 -0
  124. data/lib/apipie/swagger_generator.rb +45 -0
  125. data/lib/apipie/tag_list_description.rb +11 -0
  126. data/lib/apipie/validator.rb +552 -0
  127. data/lib/apipie/version.rb +3 -0
  128. data/lib/apipie-rails.rb +60 -0
  129. data/lib/generators/apipie/install/README +6 -0
  130. data/lib/generators/apipie/install/install_generator.rb +25 -0
  131. data/lib/generators/apipie/install/templates/initializer.rb.erb +7 -0
  132. data/lib/generators/apipie/views_generator.rb +11 -0
  133. data/lib/tasks/apipie.rake +355 -0
  134. data/rel-eng/gem_release.ipynb +398 -0
  135. data/rel-eng/packages/.readme +3 -0
  136. data/rel-eng/packages/rubygem-apipie-rails +1 -0
  137. data/rel-eng/tito.props +5 -0
  138. data/spec/controllers/api/v1/architectures_controller_spec.rb +29 -0
  139. data/spec/controllers/api/v2/architectures_controller_spec.rb +19 -0
  140. data/spec/controllers/api/v2/empty_middle_controller_spec.rb +23 -0
  141. data/spec/controllers/api/v2/nested/resources_controller_spec.rb +27 -0
  142. data/spec/controllers/api/v2/sub/footguns_controller_spec.rb +19 -0
  143. data/spec/controllers/concerns_controller_spec.rb +42 -0
  144. data/spec/controllers/extended_controller_spec.rb +14 -0
  145. data/spec/controllers/included_param_group_controller_spec.rb +13 -0
  146. data/spec/controllers/pets_controller_spec.rb +98 -0
  147. data/spec/controllers/users_controller_spec.rb +794 -0
  148. data/spec/dummy/Rakefile +7 -0
  149. data/spec/dummy/app/controllers/api/base_controller.rb +4 -0
  150. data/spec/dummy/app/controllers/api/v1/architectures_controller.rb +43 -0
  151. data/spec/dummy/app/controllers/api/v1/base_controller.rb +11 -0
  152. data/spec/dummy/app/controllers/api/v2/architectures_controller.rb +31 -0
  153. data/spec/dummy/app/controllers/api/v2/base_controller.rb +17 -0
  154. data/spec/dummy/app/controllers/api/v2/empty_middle_controller.rb +14 -0
  155. data/spec/dummy/app/controllers/api/v2/nested/architectures_controller.rb +32 -0
  156. data/spec/dummy/app/controllers/api/v2/nested/resources_controller.rb +33 -0
  157. data/spec/dummy/app/controllers/api/v2/sub/footguns_controller.rb +30 -0
  158. data/spec/dummy/app/controllers/application_controller.rb +18 -0
  159. data/spec/dummy/app/controllers/concerns_controller.rb +8 -0
  160. data/spec/dummy/app/controllers/extended_controller.rb +14 -0
  161. data/spec/dummy/app/controllers/extending_concern.rb +10 -0
  162. data/spec/dummy/app/controllers/files_controller.rb +5 -0
  163. data/spec/dummy/app/controllers/included_param_group_controller.rb +19 -0
  164. data/spec/dummy/app/controllers/overridden_concerns_controller.rb +31 -0
  165. data/spec/dummy/app/controllers/pets_controller.rb +408 -0
  166. data/spec/dummy/app/controllers/pets_using_auto_views_controller.rb +73 -0
  167. data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +95 -0
  168. data/spec/dummy/app/controllers/sample_controller.rb +39 -0
  169. data/spec/dummy/app/controllers/tagged_cats_controller.rb +32 -0
  170. data/spec/dummy/app/controllers/tagged_dogs_controller.rb +15 -0
  171. data/spec/dummy/app/controllers/twitter_example_controller.rb +307 -0
  172. data/spec/dummy/app/controllers/users_controller.rb +310 -0
  173. data/spec/dummy/app/helpers/random_param_group.rb +8 -0
  174. data/spec/dummy/app/views/layouts/application.html.erb +21 -0
  175. data/spec/dummy/components/test_engine/Gemfile +6 -0
  176. data/spec/dummy/components/test_engine/app/controllers/test_engine/application_controller.rb +4 -0
  177. data/spec/dummy/components/test_engine/app/controllers/test_engine/memes_controller.rb +37 -0
  178. data/spec/dummy/components/test_engine/config/routes.rb +3 -0
  179. data/spec/dummy/components/test_engine/db/.gitkeep +0 -0
  180. data/spec/dummy/components/test_engine/lib/test_engine.rb +7 -0
  181. data/spec/dummy/components/test_engine/test_engine.gemspec +11 -0
  182. data/spec/dummy/config/application.rb +47 -0
  183. data/spec/dummy/config/boot.rb +12 -0
  184. data/spec/dummy/config/database.yml +21 -0
  185. data/spec/dummy/config/environment.rb +8 -0
  186. data/spec/dummy/config/environments/development.rb +25 -0
  187. data/spec/dummy/config/environments/production.rb +49 -0
  188. data/spec/dummy/config/environments/test.rb +33 -0
  189. data/spec/dummy/config/initializers/apipie.rb +110 -0
  190. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  191. data/spec/dummy/config/initializers/inflections.rb +10 -0
  192. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  193. data/spec/dummy/config/initializers/secret_token.rb +8 -0
  194. data/spec/dummy/config/initializers/session_store.rb +8 -0
  195. data/spec/dummy/config/locales/en.yml +5 -0
  196. data/spec/dummy/config/routes.rb +61 -0
  197. data/spec/dummy/config.ru +4 -0
  198. data/spec/dummy/db/.gitkeep +0 -0
  199. data/spec/dummy/doc/apipie_examples.json +1 -0
  200. data/spec/dummy/doc/users/desc_from_file.md +1 -0
  201. data/spec/dummy/public/404.html +26 -0
  202. data/spec/dummy/public/422.html +26 -0
  203. data/spec/dummy/public/500.html +26 -0
  204. data/spec/dummy/public/favicon.ico +0 -0
  205. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  206. data/spec/dummy/script/rails +6 -0
  207. data/spec/lib/apipie/apipies_controller_spec.rb +345 -0
  208. data/spec/lib/apipie/application_spec.rb +62 -0
  209. data/spec/lib/apipie/configuration_spec.rb +38 -0
  210. data/spec/lib/apipie/extractor/collector_spec.rb +57 -0
  211. data/spec/lib/apipie/extractor/recorder/middleware_spec.rb +44 -0
  212. data/spec/lib/apipie/extractor/recorder_spec.rb +77 -0
  213. data/spec/lib/apipie/extractor/writer_spec.rb +112 -0
  214. data/spec/lib/apipie/extractor_spec.rb +9 -0
  215. data/spec/lib/apipie/file_handler_spec.rb +25 -0
  216. data/spec/lib/apipie/generator/swagger/config_spec.rb +19 -0
  217. data/spec/lib/apipie/generator/swagger/context_spec.rb +56 -0
  218. data/spec/lib/apipie/generator/swagger/method_description/api_schema_service_spec.rb +119 -0
  219. data/spec/lib/apipie/generator/swagger/method_description/response_schema_service_spec.rb +105 -0
  220. data/spec/lib/apipie/generator/swagger/method_description/response_service_spec.rb +62 -0
  221. data/spec/lib/apipie/generator/swagger/operation_id_spec.rb +63 -0
  222. data/spec/lib/apipie/generator/swagger/param_description/builder_spec.rb +245 -0
  223. data/spec/lib/apipie/generator/swagger/param_description/composite_spec.rb +95 -0
  224. data/spec/lib/apipie/generator/swagger/param_description/description_spec.rb +79 -0
  225. data/spec/lib/apipie/generator/swagger/param_description/in_spec.rb +86 -0
  226. data/spec/lib/apipie/generator/swagger/param_description/name_spec.rb +81 -0
  227. data/spec/lib/apipie/generator/swagger/param_description/type_spec.rb +210 -0
  228. data/spec/lib/apipie/generator/swagger/param_description_spec.rb +28 -0
  229. data/spec/lib/apipie/generator/swagger/path_decorator_spec.rb +57 -0
  230. data/spec/lib/apipie/generator/swagger/referenced_definitions_spec.rb +35 -0
  231. data/spec/lib/apipie/generator/swagger/resource_description_composite_spec.rb +37 -0
  232. data/spec/lib/apipie/generator/swagger/resource_descriptions_collection_spec.rb +57 -0
  233. data/spec/lib/apipie/generator/swagger/schema_spec.rb +89 -0
  234. data/spec/lib/apipie/generator/swagger/type_extractor_spec.rb +38 -0
  235. data/spec/lib/apipie/generator/swagger/warning_spec.rb +51 -0
  236. data/spec/lib/apipie/generator/swagger/warning_writer_spec.rb +71 -0
  237. data/spec/lib/apipie/method_description/apis_service_spec.rb +60 -0
  238. data/spec/lib/apipie/method_description_spec.rb +133 -0
  239. data/spec/lib/apipie/no_documented_method_spec.rb +17 -0
  240. data/spec/lib/apipie/param_description/deprecation_spec.rb +31 -0
  241. data/spec/lib/apipie/param_description_spec.rb +671 -0
  242. data/spec/lib/apipie/param_group_spec.rb +61 -0
  243. data/spec/lib/apipie/resource_description_spec.rb +91 -0
  244. data/spec/lib/apipie/response_description/response_object_spec.rb +22 -0
  245. data/spec/lib/apipie/response_description_spec.rb +56 -0
  246. data/spec/lib/apipie/response_does_not_match_swagger_schema_spec.rb +35 -0
  247. data/spec/lib/apipie/swagger_generator_spec.rb +94 -0
  248. data/spec/lib/apipie/validator_spec.rb +149 -0
  249. data/spec/lib/rake_spec.rb +69 -0
  250. data/spec/lib/swagger/openapi_2_0_schema.json +1614 -0
  251. data/spec/lib/swagger/rake_swagger_spec.rb +159 -0
  252. data/spec/lib/swagger/swagger_dsl_spec.rb +664 -0
  253. data/spec/lib/validators/array_validator_spec.rb +85 -0
  254. data/spec/spec_helper.rb +92 -0
  255. data/spec/support/custom_bool_validator.rb +17 -0
  256. data/spec/support/rake.rb +21 -0
  257. data/spec/test_engine/memes_controller_spec.rb +10 -0
  258. metadata +499 -0
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec path: '.'
6
+
7
+ # use ENV vars, with default value as fallback for local setup
8
+ gem 'actionpack', "~> #{ENV['RAILS_VERSION'] || '7.1'}.0"
9
+ gem 'activesupport', "~> #{ENV['RAILS_VERSION'] || '7.1'}.0"
10
+
11
+ gem 'mime-types' # , '~> 3.0'
12
+ gem 'rails-controller-testing'
13
+ gem 'rspec-rails' # , '~> 5.0'
14
+
15
+ # net-smtp not included by default in Ruby 3.1
16
+ # Will be fixed by https://github.com/mikel/mail/pull/1439
17
+ gem 'net-smtp', require: false if Gem.ruby_version >= Gem::Version.new('3.1.0')
18
+
19
+ gem 'test_engine', path: './spec/dummy/components/test_engine', group: :test
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 Pavel Pokorný
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/NOTICE ADDED
@@ -0,0 +1,4 @@
1
+ This gem is released under MIT license. Copy is included in file MIT-LICENSE.
2
+
3
+ Twitter Bootstrap and google-code-prettify are licensed under Apache License
4
+ 2.0. Copy is included in file APACHE-LICENSE-2.0.
@@ -0,0 +1,244 @@
1
+ # Proposal for supporting response descriptions in Apipie
2
+
3
+ ## Rationale
4
+
5
+ Swagger allows API authors to describe the structure of objects returned by REST API calls.
6
+ Client authors and code generators can use such descriptions for various purposes, such as verification,
7
+ autocompletion, and so forth.
8
+
9
+ The current Apipie DSL allows API authors to indicate returned error codes (using the `error` keyword),
10
+ but does not support descriptions of returned data objects. As such, swagger files
11
+ generated from the DSL do not include those, and are somewhat limited in their value.
12
+
13
+ This document proposes a minimalistic approach to extending the Apipie DSL to allow description of response
14
+ objects, and including those descriptions in generated swagger files.
15
+
16
+ ## Design Objectives
17
+
18
+ * Full backward compatibility with the existing DSL
19
+ * Minimal implementation effort
20
+ * Enough expressiveness to support common use cases
21
+ * Optional integration of the DSL with advanced JSON generators (such as Grape-Entity)
22
+ * Allowing developers to easily verify that actual responses match the response declarations
23
+
24
+ ## Approach
25
+
26
+ #### Add a `returns` keyword to the DSL, based on the existing `error` keyword
27
+
28
+ Currently, returned error codes are indicated using the `error` keyword, for example:
29
+ ```ruby
30
+ api :GET, "/users/:id", "Show user profile"
31
+ error :code => 401, :desc => "Unauthorized"
32
+ ```
33
+
34
+ The proposed approach is to add a `returns` keyword, that has the following syntax:
35
+ ```ruby
36
+ returns <type-identifier> [, :code => <number>] [, :desc => <response-description>]
37
+ ```
38
+
39
+ For example:
40
+ ```ruby
41
+ api :GET, "/users/:id", "Show user profile"
42
+ error :code => 401, :desc => "Unauthorized"
43
+ returns :SomeTypeIdentifier # :code is not specified, so it is assumed to be 200
44
+ ```
45
+
46
+
47
+ #### Leverage `param_group` for response object description
48
+
49
+ Apipie currently has a mechanism for describing complex objects using the `param_group` keyword.
50
+ It seems reasonable to leverage this mechanism as the basis of the response object description mechanism,
51
+ so that the `<type-identifier>` in the `returns` keyword will be the name of a param_group.
52
+
53
+ For example:
54
+ ```ruby
55
+ def_param_group :user do
56
+ param :user, Hash, :desc => "User info", :required => true, :action_aware => true do
57
+ param_group :credentials
58
+ param :membership, ["standard","premium"], :desc => "User membership", :allow_nil => false
59
+ end
60
+ end
61
+
62
+ api :GET, "/users/:id", "Get user record"
63
+ returns :user, "the requested record"
64
+ error :code => 404, :desc => "no user with the specified id"
65
+ ```
66
+
67
+ Implementation of this DSL extension would involve - as part of the implementation of the `returns` keyword -
68
+ the generation of a Apipie::ParamDescription object that has a Hash validator pointing to the param_group block.
69
+
70
+ #### Extend action-aware functionality to include 'response-only' parameters
71
+
72
+ In CRUD operations, it is common for `param_group` input definitions to be very similar to the
73
+ output of the API, with the exception of a very small number of fields (such as the `:id` field
74
+ which usually appears in the response, but is not described in the `param_group` because it is passed as a
75
+ path parameter).
76
+
77
+ To allow reuse of the `param_group`, it would be useful to its definition to describe parameters that are not passed
78
+ in the request but are returned in the response. This would be implementing by extending the DSL to
79
+ support a `:only_in => :response` option on `param` definitions. Similarly, params could be defined to be
80
+ `:only_in => :request` to indicate that they will not be included in the response.
81
+
82
+ For example:
83
+ ```ruby
84
+ # in the following group, the :id param is ignored in requests, but included in responses
85
+ def_param_group :user do
86
+ param :user, Hash, :desc => "User info", :required => true, :action_aware => true do
87
+ param :id, Integer, :only_in => :response
88
+ param :requested_id, Integer, :only_in => :request
89
+ param_group :credentials
90
+ param :membership, ["standard","premium"], :desc => "User membership", :allow_nil => false
91
+ end
92
+ end
93
+
94
+ api :GET, "/users/:id", "Get user record"
95
+ returns :user, :desc => "the requested record" # includes the :id field, because this is a response
96
+ error :code => 404, :desc => "no user with the specified id"
97
+ ```
98
+
99
+
100
+ #### Support `:array_of => <param_group-name>` in the `returns` keyword
101
+
102
+ Very often, a REST API call returns an array of some previously-defined object
103
+ (the most common example an `index` operation that returns an array of the same entity returned by a `show` request),
104
+ and it would be tedious to have to define a separate `param_group` for each one.
105
+
106
+ For added convenience, the `returns` keyword will also support an `:array_of =>` construct
107
+ to specify that an API call returns an array of some object type.
108
+
109
+ For example:
110
+ ```ruby
111
+ api :GET, "/users", "Get all user records"
112
+ returns :array_of => :user, :desc => "the requested user records"
113
+
114
+ api :GET, "/user/:id", "Get a single user record"
115
+ returns :user, :desc => "the requested user record"
116
+ ```
117
+
118
+ #### Integration with advanced JSON generators using an [adapter](https://en.wikipedia.org/wiki/Adapter_pattern) to `param_group`
119
+
120
+ While it makes sense for the sake of simplicity to leverage the `param_group` construct to describe
121
+ returned objects, it is likely that many developers will prefer to unify the
122
+ description of the response with the actual generation of the JSON.
123
+
124
+ Some JSON-generation libraries, such as [Grape-Entity](https://github.com/ruby-grape/grape-entity),
125
+ provide a declarative interface for describing an object model, allowing both runtime
126
+ generation of the response, as well as the ability to traverse the description to auto-generate
127
+ documentation.
128
+
129
+ Such libraries could be integrated with Apipie using adapters that wrap the library-specific
130
+ object description and expose an API that includes a `params_ordered` method that behaves in a
131
+ similar manner to [`Apipie::HashValidator.params_ordered`](https://github.com/Apipie/apipie-rails/blob/cfb42198bc39b5b30d953ba5a8b523bafdb4f897/lib/apipie/validator.rb#L315).
132
+ Such an adapter would make it possible to pass an externally-defined entity to the `returns` keyword
133
+ as if it were a `param_group`.
134
+
135
+ Such adapters can be created easily by having a class respond to `#describe_own_properties`
136
+ with an array of property description objects. When such a class is specified as the
137
+ parameter to a `returns` declaration, Apipie would query the class for its properties
138
+ by calling `<Class>#describe_own_properties`.
139
+
140
+ For example:
141
+ ```ruby
142
+ # here is a class that can describe itself to Apipie
143
+ class Animal
144
+ def self.describe_own_properties
145
+ [
146
+ Apipie::prop(:id, Integer, {:description => 'Name of pet', :required => false}),
147
+ Apipie::prop(:animal_type, 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
148
+ Apipie::additional_properties(false)
149
+ ]
150
+ end
151
+
152
+ attr_accessor :id
153
+ attr_accessor :animal_type
154
+ end
155
+
156
+ # Here is an API defined as returning Animal objects.
157
+ # Apipie creates an internal adapter by querying Animal#describe_own_properties
158
+ api :GET, "/animals", "Get all records"
159
+ returns :array_of => Animal, :desc => "the requested records"
160
+ ```
161
+
162
+ The `#describe_own_properties` mechanism can also be used with reflection so that a
163
+ class would query its own properties and populate the response to `#describe_own_properties`
164
+ automatically. See [this gist](https://gist.github.com/elasti-ron/ac145b2c85547487ca33e5216a69f527)
165
+ for an example of how Grape::Entity classes can automatically describe itself to Apipie
166
+
167
+ #### Response validation
168
+
169
+ The swagger definitions created by Apipie can be used to auto-generate clients that access the
170
+ described APIs. Those clients will break if the responses returned from the API do not match
171
+ the declarations. As such, it is very important to include unit tests that validate the actual
172
+ responses against the swagger definitions.
173
+
174
+ The ~~proposed~~ implemented mechanism provides two ways to include such validations in RSpec unit tests:
175
+ manual (using an RSpec matcher) and automated (by injecting a test into the http operations 'get', 'post',
176
+ raising an error if there is no match).
177
+
178
+ Example of the manual mechanism:
179
+
180
+ ```ruby
181
+ require 'apipie/rspec/response_validation_helper'
182
+
183
+ RSpec.describe MyController, :type => :controller, :show_in_doc => true do
184
+
185
+ describe "GET stuff with response validation" do
186
+ render_views # this makes sure the 'get' operation will actually
187
+ # return the rendered view even though this is a Controller spec
188
+
189
+ it "does something" do
190
+ response = get :index, {format: :json}
191
+
192
+ # the following expectation will fail if the returned object
193
+ # does not match the 'returns' declaration in the Controller,
194
+ # or if there is no 'returns' declaration for the returned
195
+ # HTTP status code
196
+ expect(response).to match_declared_responses
197
+ end
198
+ end
199
+ ```
200
+
201
+
202
+ Example of the automated mechanism:
203
+ ```ruby
204
+ require 'apipie/rspec/response_validation_helper'
205
+
206
+ RSpec.describe MyController, :type => :controller, :show_in_doc => true do
207
+
208
+ describe "GET stuff with response validation" do
209
+ render_views
210
+ auto_validate_rendered_views
211
+
212
+ it "does something" do
213
+ get :index, {format: :json}
214
+ end
215
+ it "does something else" do
216
+ get :another_index, {format: :json}
217
+ end
218
+ end
219
+
220
+ describe "GET stuff without response validation" do
221
+ it "does something" do
222
+ get :index, {format: :json}
223
+ end
224
+ it "does something else" do
225
+ get :another_index, {format: :json}
226
+ end
227
+ end
228
+ ```
229
+
230
+ Explanation of the implementation approach:
231
+
232
+ The Apipie Swagger Generator is enhanced to allow extraction of the JSON schema of the response object
233
+ for any controller#action[http-status]. When validation is required, the validator receives the
234
+ actual response object (along with information about the controller, action and http status code),
235
+ queries the swagger generator to get the schema, and uses the json-schema validator (gem) to validate
236
+ one against the other.
237
+
238
+ Note that there is a slight complication here: while supported by JSON-shema, the Swagger 2.0
239
+ specification does not support a mechanism to declare that fields in the response could be null.
240
+ As such, for a response that contains `null` fields, if the exact same schema used in the swagger def
241
+ is passed to the json-schema validator, the validation fails. To work around this issue, when asked
242
+ to provide the schema for the purpose of response validation (i.e., not for inclusion in the swagger),
243
+ the Apipie Swagger Generator creates a slightly modified schema which declares null values to be valid.
244
+