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/README.md ADDED
@@ -0,0 +1,2088 @@
1
+ # API Documentation Tool
2
+
3
+ [![image](https://github.com/Apipie/apipie-rails/actions/workflows/build.yml/badge.svg)](https://github.com/Apipie/apipie-rails/actions/workflows/build.yml)
4
+ [![image](https://codeclimate.com/github/Apipie/apipie-rails.svg)](https://codeclimate.com/github/Apipie/apipie-rails)
5
+ [![Join the chat at https://gitter.im/Apipie/apipie-rails](https://badges.gitter.im/Apipie/apipie-rails.svg)](https://gitter.im/Apipie/apipie-rails?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6
+ [![Latest release](https://img.shields.io/gem/v/apipie-rails.svg)](https://rubygems.org/gems/apipie-rails)
7
+
8
+ Apipie-rails is a DSL and Rails engine for documenting your RESTful API.
9
+ Instead of traditional use of `#comments`, Apipie lets you describe the
10
+ code, through the code. This brings advantages like:
11
+
12
+ - No need to learn yet another syntax, you already know Ruby, right?
13
+ - Possibility of reusing the docs for other purposes (such as
14
+ validation)
15
+ - Easier to extend and maintain (no string parsing involved)
16
+ - Possibility of reusing other sources for documentation purposes
17
+ (such as routes etc.)
18
+
19
+ The documentation is available from within your app (by default under
20
+ the `/apipie` path.) In development mode, you can see the changes as you
21
+ go. It\'s markup language agnostic, and even provides an API for reusing
22
+ the documentation data in JSON.
23
+
24
+ ## Getting started
25
+
26
+ The easiest way to get Apipie up and running with your app is:
27
+
28
+ ``` sh
29
+ echo "gem 'apipie-rails'" >> Gemfile
30
+ bundle install
31
+ rails g apipie:install
32
+ ```
33
+
34
+ Now you can start documenting your resources and actions (see [DSL
35
+ Reference](#dsl-reference) for more info):
36
+
37
+ ``` ruby
38
+ api :GET, '/users/:id'
39
+ param :id, :number, desc: 'id of the requested user'
40
+ def show
41
+ # ...
42
+ end
43
+ ```
44
+
45
+ Run your application and see the result at
46
+ `http://localhost:3000/apipie`. For further processing, you can use
47
+ `http://localhost:3000/apipie.json`.
48
+
49
+ For a more comprehensive getting started guide, see [this
50
+ demo](https://github.com/Apipie/apipie-demo), which includes features
51
+ such as generating documentation from tests, recording examples etc.
52
+
53
+ ## Screenshots
54
+
55
+ ![image](https://github.com/Apipie/apipie-rails/blob/master/images/screenshot-1.png)
56
+
57
+ ![image](https://github.com/Apipie/apipie-rails/blob/master/images/screenshot-2.png)
58
+
59
+ ## Authors
60
+
61
+ [Pajk](https://github.com/Pajk) and [iNecas](https://github.com/iNecas)
62
+
63
+ ## Contributors
64
+
65
+ See [Contributors
66
+ page](https://github.com/Apipie/apipie-rails/graphs/contributors).
67
+ Special thanks to all of them!
68
+
69
+ ## License
70
+
71
+ Apipie-rails is released under the [MIT
72
+ License](https://opensource.org/licenses/MIT)
73
+
74
+ ## Table Of Contents
75
+
76
+ - [API Documentation Tool](#api-documentation-tool)
77
+ - [Getting started](#getting-started)
78
+ - [Screenshots](#screenshots)
79
+ - [Authors](#authors)
80
+ - [Contributors](#contributors)
81
+ - [License](#license)
82
+ - [Documentation](#documentation)
83
+ - [DSL Reference](#dsl-reference)
84
+ - [Resource Description](#resource-description)
85
+ - [Method Description](#method-description)
86
+ - [Parameter Description](#parameter-description)
87
+ - [DRY with param_group](#dry-with-param_group)
88
+ - [Action Aware params](#action-aware-params)
89
+ - [Response Description](#response-description)
90
+ - [Concerns](#concerns)
91
+ - [Response validation](#response-validation)
92
+ - [Configuration Reference](#configuration-reference)
93
+ - [Rails Routes Integration](#rails-routes-integration)
94
+ - [Processing](#processing)
95
+ - [Validators](#validators)
96
+ - [TypeValidator](#typevalidator)
97
+ - [RegexpValidator](#regexpvalidator)
98
+ - [EnumValidator](#enumvalidator)
99
+ - [ProcValidator](#procvalidator)
100
+ - [HashValidator](#hashvalidator)
101
+ - [NilValidator](#nilvalidator)
102
+ - [NumberValidator](#numbervalidator)
103
+ - [DecimalValidator](#decimalvalidator)
104
+ - [ArrayValidator](#arrayvalidator)
105
+ - [NestedValidator](#nestedvalidator)
106
+ - [Adding custom validator](#adding-custom-validator)
107
+ - [Versioning](#versioning)
108
+ - [Markup](#markup)
109
+ - [Localization](#localization)
110
+ - [Modifying Views](#modifying-views)
111
+ - [Static files](#static-files)
112
+ - [Static Swagger (OpenAPI 2.0) files](#static-swagger-openapi-20-files)
113
+ - [Specifying default values for parameters](#specifying-default-values-for-parameters)
114
+ - [Generated Warnings](#generated-warnings)
115
+ - [Swagger-Specific Configuration Parameters](#swagger-specific-configuration-parameters)
116
+ - [Known limitations of the current implementation](#known-limitations-of-the-current-implementation)
117
+ - [Dynamic Swagger generation](#dynamic-swagger-generation)
118
+ - [JSON checksums](#json-checksums)
119
+ - [Tests Integration](#tests-integration)
120
+ - [Documentation Bootstrapping](#documentation-bootstrapping)
121
+ - [Examples Recording](#examples-recording)
122
+ - [Caveats](#caveats)
123
+ - [Bindings Generator](#bindings-generator)
124
+ - [Contributing](#contributing)
125
+ - [Disqus Integration](#disqus-integration)
126
+ - [External References](#external-references)
127
+
128
+ # DSL Reference
129
+
130
+ ## Resource Description
131
+
132
+ You can describe a resource on the controller level. The description is
133
+ introduced by calling `resource_description do ... end`.
134
+
135
+ Inheritance is supported, so you can specify common params for group of
136
+ controllers in their parent class.
137
+
138
+ The following keywords are available (all are optional):
139
+
140
+ `resource_id`
141
+
142
+ How the resource will be referenced in Apipie (paths, `see` command etc.); by default `controller_name.downcase` is used.
143
+
144
+ `name`
145
+
146
+ Human readable name of resource. By default `class.name.humanize` is
147
+ used.
148
+
149
+ - Can be specified as a proc, which will receive the controller
150
+ class as an argument.
151
+ - Can be a symbol, which will be sent to the controller class to
152
+ get the name.
153
+ - Can be a string, which will be used as is.
154
+
155
+ `short` (also `short_description`)
156
+
157
+ Short description of the resource (it\'s shown on both the list of resources, and resource details)
158
+
159
+ `desc` (also description and full_description)
160
+
161
+ Full description of the resource (shown only in resource details)
162
+
163
+ `param`
164
+
165
+ Common params for all methods defined in controller/child controllers.
166
+
167
+ `returns`
168
+
169
+ Common responses for all methods defined in controller/child controllers.
170
+
171
+ `api_base_url`
172
+
173
+ What URL is the resource available under.
174
+
175
+ `api_versions` (also api_version)
176
+
177
+ What versions does the controller define the resource. (See [Versioning](#versioning) for details.)
178
+
179
+ `formats`
180
+
181
+ Request / response formats.
182
+
183
+ `error`
184
+
185
+ Describe every possible error that can happen when calling all
186
+ methods defined in controller. HTTP response code and description
187
+ can be provided.
188
+
189
+ `app_info`
190
+
191
+ In case of versioning, this sets app info description on a per_version basis.
192
+
193
+ `meta`
194
+
195
+ Hash or array with custom metadata.
196
+
197
+ `deprecated`
198
+
199
+ Boolean value indicating if the resource is marked as deprecated. (Default `false`)
200
+
201
+ ### Example:
202
+
203
+ ``` ruby
204
+ resource_description do
205
+ short 'Site members'
206
+ formats ['json']
207
+ param :id, Integer, :desc => "User ID", :required => false
208
+ param :resource_param, Hash, :desc => 'Param description for all methods' do
209
+ param :ausername, String, :desc => "Username for login", :required => true
210
+ param :apassword, String, :desc => "Password for login", :required => true
211
+ end
212
+ api_version "development"
213
+ error 404, "Missing"
214
+ error 500, "Server crashed for some <%= reason %>", :meta => {:anything => "you can think of"}
215
+ error :unprocessable_entity, "Could not save the entity."
216
+ returns :code => 403 do
217
+ property :reason, String, :desc => "Why this was forbidden"
218
+ end
219
+ meta :author => {:name => 'John', :surname => 'Doe'}
220
+ deprecated false
221
+ description <<-EOS
222
+ == Long description
223
+ Example resource for rest api documentation
224
+ These can now be accessed in <tt>shared/header</tt> with:
225
+ Headline: <%= headline %>
226
+ First name: <%= person.first_name %>
227
+
228
+ If you need to find out whether a certain local variable has been
229
+ assigned a value in a particular render call, you need to use the
230
+ following pattern:
231
+
232
+ <% if local_assigns.has_key? :headline %>
233
+ Headline: <%= headline %>
234
+ <% end %>
235
+
236
+ Testing using <tt>defined? headline</tt> will not work. This is an
237
+ implementation restriction.
238
+
239
+ === Template caching
240
+
241
+ By default, Rails will compile each template to a method in order
242
+ to render it. When you alter a template, Rails will check the
243
+ file's modification time and recompile it in development mode.
244
+ EOS
245
+ end
246
+ ```
247
+
248
+ ## Method Description
249
+
250
+ Then describe methods available to your API.
251
+
252
+ `api`
253
+
254
+ Describe how this method is exposed, and provide a short
255
+ description. The first parameter is HTTP method (one of
256
+ :GET/:POST/:PUT/:DELETE). The second parameter is the relative URL
257
+ path which is mapped to this method. The last parameter is the
258
+ methods short description. You can use this +api+ method more than
259
+ once per method. It could be useful when there are more routes
260
+ mapped to it.
261
+
262
+ When providing just one argument (description), or no argument at
263
+ all, the paths will be loaded from the routes.rb file.
264
+
265
+ `api!`
266
+
267
+ Provide a short description and additional option. The last
268
+ parameter is the methods short description. The paths will be loaded
269
+ from routes.rb file. See [Rails Routes
270
+ Integration](#rails-routes-integration) for more details.
271
+
272
+ `api_versions` (also api_version)
273
+
274
+ What version(s) does the action belong to. (See
275
+ [Versioning](#versioning) for details.)
276
+
277
+ `param`
278
+
279
+ Look at [Parameter description](#parameter-description) section for
280
+ details.
281
+
282
+ `returns`
283
+
284
+ Look at [Response description](#response-description) section for
285
+ details.
286
+
287
+ `tags`
288
+
289
+ Adds tags for grouping operations together in Swagger outputs. See
290
+ [swagger](#Swagger) for more details. You can also provide tags in
291
+ the [Resource Description](#resource-description) block so that they
292
+ are automatically prepended to all action tags in the controller.
293
+
294
+ `formats`
295
+
296
+ Method level request / response formats.
297
+
298
+ `error`
299
+
300
+ Describe each possible error that can happen while calling this
301
+ method. HTTP response code and description can be provided.
302
+
303
+ `description`
304
+
305
+ Full method description, which will be converted into HTML by the
306
+ chosen markup language processor.
307
+
308
+ `example`
309
+
310
+ Provide an example of the server response; whole communication or
311
+ response type. It will be formatted as code.
312
+
313
+ `see`
314
+
315
+ Provide reference to another method, this has to be a string with
316
+ controller_name#method_name.
317
+
318
+ `meta`
319
+
320
+ Hash or array with custom metadata.
321
+
322
+ `show`
323
+
324
+ Resource is hidden from documentation when set to false (true by
325
+ default)
326
+
327
+ ### Example:
328
+
329
+ ``` ruby
330
+ # The simplest case: just load the paths from routes.rb
331
+ api!
332
+ def index
333
+ end
334
+
335
+ # More complex example
336
+ api :GET, "/users/:id", "Show user profile"
337
+ show false
338
+ error :code => 401, :desc => "Unauthorized"
339
+ error :code => 404, :desc => "Not Found", :meta => {:anything => "you can think of"}
340
+ param :session, String, :desc => "user is logged in", :required => true
341
+ param :regexp_param, /^[0-9]* years/, :desc => "regexp param"
342
+ param :array_param, [100, "one", "two", 1, 2], :desc => "array validator"
343
+ param :boolean_param, [true, false], :desc => "array validator with boolean"
344
+ param :proc_param, lambda { |val|
345
+ val == "param value" ? true : "The only good value is 'param value'."
346
+ }, :desc => "proc validator"
347
+ param :param_with_metadata, String, :desc => "", :meta => [:your, :custom, :metadata]
348
+ returns :code => 200, :desc => "a successful response" do
349
+ property :value1, String, :desc => "A string value"
350
+ property :value2, Integer, :desc => "An integer value"
351
+ property :value3, Hash, :desc => "An object" do
352
+ property :enum1, ['v1', 'v2'], :desc => "One of 2 possible string values"
353
+ end
354
+ end
355
+ tags %w[profiles logins]
356
+ tags 'more', 'related', 'resources'
357
+ description "method description"
358
+ formats ['json', 'jsonp', 'xml']
359
+ meta :message => "Some very important info"
360
+ example " 'user': {...} "
361
+ see "users#showme", "link description"
362
+ see :link => "users#update", :desc => "another link description"
363
+ def show
364
+ #...
365
+ end
366
+ ```
367
+
368
+ ## Parameter Description
369
+
370
+ Use `param` to describe every possible parameter. You can use the Hash
371
+ validator in conjunction with a block given to the param method to
372
+ describe nested parameters.
373
+
374
+ `name`
375
+
376
+ The first argument is the parameter name as a symbol.
377
+
378
+ `validator`
379
+
380
+ Second parameter is the parameter validator, choose one from section
381
+ [Validators](#validators)
382
+
383
+ `desc`
384
+
385
+ Parameter description.
386
+
387
+ `required`
388
+
389
+ Set this true/false to make it required/optional. Default is
390
+ optional
391
+
392
+ `example`
393
+
394
+ Provide the example for this parameter.
395
+
396
+ `allow_nil`
397
+
398
+ Setting this to true means that `nil` can be passed.
399
+
400
+ `allow_blank`
401
+
402
+ Like `allow_nil`, but for blank values. `false`, `""`, `' '`, `nil`,
403
+ `[]`, and `{}` are all blank.
404
+
405
+ `as`
406
+
407
+ Used by the processing functionality to change the name of a key params.
408
+
409
+ `meta`
410
+
411
+ Hash or array with custom metadata.
412
+
413
+ `show`
414
+
415
+ Parameter is hidden from documentation when set to false (true by default)
416
+
417
+ `missing_message`
418
+
419
+ Specify the message to be returned if the parameter is missing as a
420
+ string or Proc. Defaults to `Missing parameter #{name}` if not
421
+ specified.
422
+
423
+ `only_in`
424
+
425
+ This can be set to `:request` or `:response`. Setting to `:response`
426
+ causes the param to be ignored when used as part of a request
427
+ description. Setting to `:request` causes this param to be ignored
428
+ when used as part of a response description. If `only_in` is not
429
+ specified, the param definition is used for both requests and
430
+ responses. (Note that the keyword `property` is similar to `param`,
431
+ but it has a `:only_in => :response` default).
432
+
433
+ ### Example:
434
+
435
+ ``` ruby
436
+ param :user, Hash, :desc => "User info" do
437
+ param :username, String, :desc => "Username for login", :required => true, :example => 'John'
438
+ param :password, String, :desc => "Password for login", :required => true, :example => '1234567'
439
+ param :membership, ["standard","premium"], :desc => "User membership"
440
+ param :admin_override, String, :desc => "Not shown in documentation", :show => false
441
+ param :ip_address, String, :desc => "IP address", :required => true, :missing_message => lambda { I18n.t("ip_address.required") }
442
+ end
443
+ def create
444
+ #...
445
+ end
446
+ ```
447
+
448
+ `deprecated`
449
+
450
+ Indicates if the parameter is marked as deprecated.
451
+
452
+ ### Example
453
+
454
+ ``` ruby
455
+ param :pet_name, String, desc: "Name of pet", deprecated: true
456
+ param :pet_name, String, desc: "Name of pet", deprecated: 'Some deprecation info'
457
+ param :pet_name, String, desc: "Name of pet", deprecated: { in: "2.3", info: "Something", sunset: "3.0" }
458
+ def create
459
+ #...
460
+ end
461
+ ```
462
+
463
+ ## DRY with param_group
464
+
465
+ Often, params occur together in more actions. Typically, most of the
466
+ params for `create` and `update` actions are shared between them.
467
+
468
+ These params can be extracted with `def_param_group` and `param_group`
469
+ keywords.
470
+
471
+ The definition is looked up in the scope of the controller. If the group
472
+ is defined in a different controller, it might be referenced by
473
+ specifying the second argument.
474
+
475
+ ### Example:
476
+
477
+ ``` ruby
478
+ # v1/users_controller.rb
479
+ def_param_group :address do
480
+ param :street, String
481
+ param :number, Integer
482
+ param :zip, String
483
+ end
484
+
485
+ def_param_group :user do
486
+ param :user, Hash do
487
+ param :name, String, "Name of the user"
488
+ param_group :address
489
+ end
490
+ end
491
+
492
+ api :POST, "/users", "Create a user"
493
+ param_group :user
494
+ def create
495
+ # ...
496
+ end
497
+
498
+ api :PUT, "/users/:id", "Update a user"
499
+ param_group :user
500
+ def update
501
+ # ...
502
+ end
503
+
504
+ # v2/users_controller.rb
505
+ api :POST, "/users", "Create a user"
506
+ param_group :user, V1::UsersController
507
+ def create
508
+ # ...
509
+ end
510
+ ```
511
+
512
+ ## Action Aware params
513
+
514
+ In CRUD operations, this pattern occurs quite often - params that need
515
+ to be set are:
516
+
517
+ - for create action: `required => true` and `allow_nil => false`
518
+ - for update action: `required => false` and `allow_nil => false`
519
+
520
+ This makes it hard to share the param definitions across these actions.
521
+ Therefore, you can make the description a bit smarter by setting
522
+ `:action_aware => true`.
523
+
524
+ You can specify explicitly how the param group should be evaluated with
525
+ `:as` option (either :create or :update)
526
+
527
+ ### Example
528
+
529
+ ``` ruby
530
+ def_param_group :user do
531
+ param :user, Hash, :action_aware => true do
532
+ param :name, String, :required => true
533
+ param :description, String
534
+ end
535
+ end
536
+
537
+ api :POST, "/users", "Create a user"
538
+ param_group :user
539
+ def create
540
+ # ...
541
+ end
542
+
543
+ api :PUT, "/users/admin", "Create an admin"
544
+ param_group :user, :as => :create
545
+ def create_admin
546
+ # ...
547
+ end
548
+
549
+ api :PUT, "/users/:id", "Update a user"
550
+ param_group :user
551
+ def update
552
+ # ...
553
+ end
554
+ ```
555
+
556
+ In this case, `user[name]` will be not be allowed nil for all actions
557
+ and required only for `create` and `create_admin`. Params with
558
+ `allow_nil` set explicitly don\'t have this value changed.
559
+
560
+ Action awareness is inherited from ancestors (in terms of nested
561
+ params).
562
+
563
+ ## Response Description
564
+
565
+ The response from an API call can be documented by adding a `returns`
566
+ statement to the method description. This is especially useful when
567
+ using Apipie to auto-generate a machine-readable Swagger definition of
568
+ your API (see the [swagger](#Swagger) section for more details).
569
+
570
+ A `returns` statement has several possible formats:
571
+
572
+ ``` ruby
573
+ # format #1: reference to a param-group
574
+ returns <param-group-name> [, :code => <number>|<http-response-code-symbol>] [, :desc => <human-readable description>]
575
+
576
+ # format #2: inline response definition
577
+ returns :code => <number>|<http-response-code-symbol> [, :desc => <human-readable description>] do
578
+ # property ...
579
+ # property ...
580
+ # param_group ...
581
+ end
582
+
583
+ # format #3: describing an array-of-objects response
584
+ returns :array_of => <param-group-name> [, :code => <number>|<http-response-code-symbol>] [, :desc => <human-readable description>]
585
+ ```
586
+
587
+ If the `:code` argument is omitted, `200` is used.
588
+
589
+ ### Example
590
+
591
+ ``` ruby
592
+ # ------------------------------------------------
593
+ # Example of format #1 (reference to param-group):
594
+ # ------------------------------------------------
595
+ # the param_group :pet is defined here to describe the output returned by the method below.
596
+ def_param_group :pet do
597
+ property :pet_name, String, :desc => "Name of pet"
598
+ property :animal_type, ['dog','cat','iguana','kangaroo'], :desc => "Type of pet"
599
+ end
600
+
601
+ api :GET, "/pets/:id", "Get a pet record"
602
+ returns :pet, :desc => "The pet"
603
+ def show_detailed
604
+ render JSON({:pet_name => "Skippie", :animal_type => "kangaroo"})
605
+ end
606
+
607
+ # ------------------------------------------------
608
+ # Example of format #2 (inline):
609
+ # ------------------------------------------------
610
+ api :GET, "/pets/:id/with-extra-details", "Get a detailed pet record"
611
+ returns :code => 200, :desc => "Detailed info about the pet" do
612
+ param_group :pet
613
+ property :num_legs, Integer, :desc => "How many legs the pet has"
614
+ end
615
+ def show
616
+ render JSON({:pet_name => "Barkie", :animal_type => "iguana", :legs => 4})
617
+ end
618
+
619
+ # ------------------------------------------------
620
+ # Example of format #3 (array response):
621
+ # ------------------------------------------------
622
+ api :GET, "/pets", "Get all pet records"
623
+ returns :array_of => :pet, :code => 200, :desc => "All pets"
624
+ def index
625
+ render JSON([ {:pet_name => "Skippie", :animal_type => "kangaroo"},
626
+ {:pet_name => "Woofie", :animal_type => "cat"} ])
627
+ end
628
+ ```
629
+
630
+ Note the use of the `property` keyword rather than `param`. This is the
631
+ preferred mechanism for documenting response-only fields.
632
+
633
+ #### Specify response headers
634
+
635
+ We can specify the response headers using the `header` keyword within the `returns` block.
636
+
637
+ ##### Example
638
+ ```ruby
639
+ api :GET, "/pets/:id/with-extra-details", "Get a detailed pet record"
640
+ returns code: 200, desc: "Detailed info about the pet" do
641
+ param_group :pet
642
+ property :num_legs, Integer, :desc => "How many legs the pet has"
643
+ header 'Link', String, 'Relative links'
644
+ header 'Current-Page', Integer, 'The current page', required: true
645
+ end
646
+
647
+ def show
648
+ render JSON({ :pet_name => "Barkie", :animal_type => "iguana", :legs => 4 })
649
+ end
650
+ ```
651
+
652
+ #### The Property keyword
653
+
654
+ `property` is very similar to `param` with the following differences:
655
+
656
+ - a `property` is `:only_in => :response` by default
657
+ - a `property` is `:required => :true` by default
658
+ - a `property` can be an `:array_of` objects
659
+
660
+ ##### Example
661
+
662
+ ``` ruby
663
+ property :example, :array_of => Hash do
664
+ property :number1, Integer
665
+ property :number2, Integer
666
+ end
667
+ ```
668
+
669
+ #### Describing multiple return codes
670
+
671
+ To describe multiple possible return codes, the `:returns` keyword can
672
+ be repeated as many times as necessary (once for each return code). Each
673
+ one of the `:returns` entries can specify a different response format.
674
+
675
+ ##### Example
676
+
677
+ ``` ruby
678
+ api :GET, "/pets/:id/extra_info", "Get extra information about a pet"
679
+ returns :desc => "Found a pet" do
680
+ param_group :pet
681
+ property 'pet_history', Hash do
682
+ param_group :pet_history
683
+ end
684
+ end
685
+ returns :code => :unprocessable_entity, :desc => "Fleas were discovered on the pet" do
686
+ param_group :pet
687
+ property :num_fleas, Integer, :desc => "Number of fleas on this pet"
688
+ end
689
+ def show_extra_info
690
+ # ... implementation here
691
+ end
692
+ ```
693
+
694
+ #### Reusing a param_group to describe inputs and outputs
695
+
696
+ In many cases (such as CRUD implementations), the output from certain
697
+ API calls is very similar - but not identical - to the inputs of the
698
+ same or other API calls.
699
+
700
+ If you already have a `:param_group` that defines the input to a
701
+ `create` or `update routine, it would be quite
702
+ frustrating to have to define a completely separate `:param_group` to
703
+ describe the output of the `show` routine.
704
+
705
+ To address such situations, it is possible to define a single
706
+ `:param_group` which combines `param` and `property` statements (as well
707
+ as `:only_in => :request` / `:only_in => :response`) to differentiate
708
+ between fields that are only expected in the request, only included in
709
+ the response, or common to both.
710
+
711
+ This is somewhat analogous to the way [Action Aware
712
+ params](#action-aware-params) work.
713
+
714
+ ##### Example
715
+
716
+ ``` ruby
717
+ def_param_group :user_record
718
+ param :name, String # this is commong to both the request and the response
719
+ param :force_update, [true, false], :only_in => :request # this does not show up in responses
720
+ property :last_login, String # this shows up only in the response
721
+ end
722
+
723
+ api :POST, "/users", "Create a user"
724
+ param_group :user_record # the :last_login field is not expected here, but :force_update is
725
+ def create
726
+ # ...
727
+ end
728
+
729
+ api :GET, "/users", "Create a user"
730
+ returns :array_of => :user_record # the :last_login field will be included in the response, but :force_update will not
731
+ def index
732
+ # ...
733
+ end
734
+ ```
735
+
736
+ #### Embedded response descriptions
737
+
738
+ If the code creating JSON responses is encapsulated within dedicated
739
+ classes, it can be more convenient to place the response descriptions
740
+ outside of the controller and embed them within the response generator.
741
+
742
+ To support such use cases, Apipie allows any class to provide a
743
+ `describe_own_properties` class method which returns a
744
+ description of the properties such a class would expose. It is then
745
+ possible to specify that class in the `returns` statement
746
+ instead of a `param_group`.
747
+
748
+ The `describe_own_properties` method is expected to return
749
+ an array of `Apipie::prop` objects, each one describing a
750
+ single property.
751
+
752
+ ##### Example
753
+
754
+ ``` ruby
755
+ class Pet
756
+ # this method is automatically called by Apipie when Pet is specified as the returned object type
757
+ def self.describe_own_properties
758
+ [
759
+ Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
760
+ Apipie::prop(:animal_type, 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
761
+ Apipie::additional_properties(false) # this indicates that :pet_name and :animal_type are the only properties in the response
762
+ ]
763
+ end
764
+
765
+ # this method w
766
+ def json
767
+ JSON({:pet_name => @name, :animal_type => @type })
768
+ end
769
+ end
770
+
771
+
772
+ class PetsController
773
+ api :GET, "/index", "Get all pets"
774
+ returns :array_of => Pet # Pet is a 'self-describing-class'
775
+ def index
776
+ # ...
777
+ end
778
+ end
779
+ ```
780
+
781
+ A use case where this is very useful is when JSON generation is done
782
+ using a reflection mechanism or some other sort of declarative
783
+ mechanism.
784
+
785
+ The `Apipie::prop` function expects the following inputs:
786
+
787
+ ``` ruby
788
+ Apipie::prop(<property-name>, <property-type>, <options-hash> [, <array of sub-properties>])
789
+
790
+ # property-name should be a symbol
791
+ #
792
+ # property-type can be any of the following strings:
793
+ # "integer": maps to a swagger "integer" with an "int32" format
794
+ # "long": maps to a swagger "integer" with an "int64" format
795
+ # "number": maps to a swagger "number"(no format specifier)
796
+ # "float": maps to a swagger "number" with a "float" format
797
+ # "double": maps to a swagger "number" with a "double" format
798
+ # "string": maps to a swagger "string" (no format specifier)
799
+ # "byte": maps to a swagger "string" with a "byte" format
800
+ # "binary": maps to a swagger "string" with a "binary" format
801
+ # "boolean": maps to a swagger "boolean" (no format specifier)
802
+ # "date": maps to a swagger "string" with a "date" format
803
+ # "dateTime": maps to a swagger "string" with a "date-time" format
804
+ # "password": maps to a swagger "string" with a "password" format
805
+ # "object": the property has sub-properties. include <array of sub-properties> in the call.
806
+ # (see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more information
807
+ # about the mapped swagger types)
808
+ #
809
+ # options-hash can include any of the options fields allowed in a :returns statement.
810
+ # additionally, it can include the ':is_array => true', in which case the property is understood to be
811
+ # an array of the described type.
812
+ ```
813
+
814
+ To describe an embedded object:
815
+
816
+ ``` ruby
817
+ #
818
+ # PetWithMeasurements is a self-describing class with an embedded object
819
+ #
820
+ class PetWithMeasurements
821
+ def self.describe_own_properties
822
+ [
823
+ Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
824
+ Apipie::prop('animal_type', 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
825
+ Apipie::prop(:pet_measurements, 'object', {}, [
826
+ Apipie::prop(:weight, 'number', {:description => "Weight in pounds" }),
827
+ Apipie::prop(:height, 'number', {:description => "Height in inches" }),
828
+ Apipie::prop(:num_legs, 'number', {:description => "Number of legs", :required => false }),
829
+ Apipie::additional_properties(false)
830
+ ])
831
+ ]
832
+ end
833
+ end
834
+
835
+ #
836
+ # PetWithManyMeasurements is a self-describing class with an embedded array of objects
837
+ #
838
+ class PetWithManyMeasurements
839
+ def self.describe_own_properties
840
+ [
841
+ Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
842
+ Apipie::prop(:many_pet_measurements, 'object', {is_array: true}, [
843
+ Apipie::prop(:weight, 'number', {:description => "Weight in pounds" }),
844
+ Apipie::prop(:height, 'number', {:description => "Height in inches" }),
845
+ ])
846
+ ]
847
+ end
848
+ end
849
+ ```
850
+
851
+ ## Concerns
852
+
853
+ Sometimes, the actions are not defined in the controller class directly
854
+ but included from a module instead. You can load the Apipie DSL into the
855
+ module by extending it with `Apipie::DSL::Concern`.
856
+
857
+ The module can be used in more controllers. Therefore there is a way to
858
+ substitute parts of the documentation in the module with controller
859
+ specific values. These substitutions can be stated explicitly with
860
+ `apipie_concern_subst(:key => "value")` (needs to be called before the
861
+ module is included to take effect). The substitutions are performed in
862
+ the paths and descriptions of APIs and names and descriptions of params.
863
+
864
+ There are some default substitutions available:
865
+
866
+ `:controller_path`
867
+
868
+ value of `controller.controller_path`, e.g. `api/users` for
869
+ `Api::UsersController`. Only if not using the `api!` keyword.
870
+
871
+ `:resource_id`
872
+
873
+ Apipie identifier of the resource, e.g. `users` for
874
+ `Api::UsersController` or set by `resource_id`
875
+
876
+ ### Example
877
+
878
+ ``` ruby
879
+ # users_module.rb
880
+ module UsersModule
881
+ extend Apipie::DSL::Concern
882
+
883
+ api :GET, '/:controller_path', 'List :resource_id'
884
+ def index
885
+ # ...
886
+ end
887
+
888
+ api! 'Show a :resource'
889
+ def show
890
+ # ...
891
+ end
892
+
893
+ api :POST, '/:resource_id', "Create a :resource"
894
+ param :concern, Hash, :required => true
895
+ param :name, String, 'Name of a :resource'
896
+ param :resource_type, ['standard','vip']
897
+ end
898
+ def create
899
+ # ...
900
+ end
901
+
902
+ api :GET, '/:resource_id/:custom_subst'
903
+ def custom
904
+ # ...
905
+ end
906
+ end
907
+
908
+ # users_controller.rb
909
+ class UsersController < ApplicationController
910
+
911
+ resource_description { resource_id 'customers' }
912
+
913
+ apipie_concern_subst(:custom_subst => 'custom', :resource => 'customer')
914
+ include UsersModule
915
+
916
+ # the following paths are documented
917
+ # api :GET, '/users'
918
+ # api :GET, '/customers/:id', 'Show a customer'
919
+ # api :POST, '/customers', 'Create a customer'
920
+ # param :customer, :required => true do
921
+ # param :name, String, 'Name of a customer'
922
+ # param :customer_type, ['standard', 'vip']
923
+ # end
924
+ # api :GET, '/customers/:custom'
925
+ end
926
+ ```
927
+
928
+ Sometimes, it\'s needed to extend an existing controller method with
929
+ additional parameters (usually when extending exiting API from
930
+ plugins/rails engines). The concern can be also used for this purposed,
931
+ using `update_api` method. The params defined in this block
932
+ are merged with the params of the original method in the controller this
933
+ concern is included to.
934
+
935
+ ### Example
936
+
937
+ ``` ruby
938
+ module Concerns
939
+ module OauthConcern
940
+ extend Apipie::DSL::Concern
941
+
942
+ update_api(:create, :update) do
943
+ param :user, Hash do
944
+ param :oauth, String, :desc => 'oauth param'
945
+ end
946
+ end
947
+ end
948
+ end
949
+ ```
950
+
951
+ The concern needs to be included to the controller after the methods are
952
+ defined (either at the end of the class, or by using
953
+ `Controller.send(:include, Concerns::OauthConcern)`.
954
+
955
+ ## Response validation
956
+
957
+ The swagger definitions created by Apipie can be used to auto-generate
958
+ clients that access the described APIs. Those clients will break if the
959
+ responses returned from the API do not match the declarations. As such,
960
+ it is very important to include unit tests that validate the actual
961
+ responses against the swagger definitions.
962
+
963
+ The implemented mechanism provides two ways to include such validations
964
+ in RSpec unit tests: manual (using an RSpec matcher) and automated (by
965
+ injecting a test into the http operations \'get\', \'post\', raising an
966
+ error if there is no match).
967
+
968
+ ### Example of the manual mechanism:
969
+
970
+ ``` ruby
971
+ require 'apipie/rspec/response_validation_helper'
972
+
973
+ RSpec.describe MyController, :type => :controller, :show_in_doc => true do
974
+
975
+ describe "GET stuff with response validation" do
976
+ render_views # this makes sure the 'get' operation will actually
977
+ # return the rendered view even though this is a Controller spec
978
+
979
+ it "does something" do
980
+ response = get :index, {format: :json}
981
+
982
+ # the following expectation will fail if the returned object
983
+ # does not match the 'returns' declaration in the Controller,
984
+ # or if there is no 'returns' declaration for the returned
985
+ # HTTP status code
986
+ expect(response).to match_declared_responses
987
+ end
988
+ end
989
+ end
990
+ ```
991
+
992
+ ### Example of the automated mechanism:
993
+
994
+ ``` ruby
995
+ require 'apipie/rspec/response_validation_helper'
996
+
997
+ RSpec.describe MyController, :type => :controller, :show_in_doc => true do
998
+
999
+ describe "GET stuff with response validation" do
1000
+ render_views
1001
+ auto_validate_rendered_views
1002
+
1003
+ it "does something" do
1004
+ get :index, {format: :json}
1005
+ end
1006
+ it "does something else" do
1007
+ get :another_index, {format: :json}
1008
+ end
1009
+ end
1010
+
1011
+ describe "GET stuff without response validation" do
1012
+ it "does something" do
1013
+ get :index, {format: :json}
1014
+ end
1015
+ it "does something else" do
1016
+ get :another_index, {format: :json}
1017
+ end
1018
+ end
1019
+ end
1020
+ ```
1021
+
1022
+ # Configuration Reference
1023
+
1024
+ Create a configuration file in e.g. `/config/initializers/apipie.rb`.
1025
+ You can set the application name, footer text, API and documentation
1026
+ base URL and turn off validations. You can also choose your favorite
1027
+ markup language for full descriptions.
1028
+
1029
+ `app_name`
1030
+
1031
+ Name of your application; used in breadcrumbs navigation.
1032
+
1033
+ `copyright`
1034
+
1035
+ Copyright information (shown in page footer).
1036
+
1037
+ `compress_examples`
1038
+
1039
+ If `true` recorded examples are compressed using `Zlib`. Useful for
1040
+ big test-suits.
1041
+
1042
+ `doc_base_url`
1043
+
1044
+ Documentation frontend base url.
1045
+
1046
+ `api_base_url`
1047
+
1048
+ Base url for default version of your API. To set it for specific
1049
+ version use `config.api_base_url[version] = url`.
1050
+
1051
+ `default_version`
1052
+
1053
+ Default API version to be used (1.0 by default)
1054
+
1055
+ `validate`
1056
+
1057
+ Parameters validation is turned off when set to false. When set to
1058
+ `:explicitly`, you must invoke parameter validation yourself by
1059
+ calling controller method `apipie_validations` (typically in a
1060
+ before_action). When set to `:implicitly` (or just true), your
1061
+ controller\'s action methods are wrapped with generated methods
1062
+ which call `apipie_validations`, and then call the action method.
1063
+ (`:implicitly` by default)
1064
+
1065
+ `validate_value`
1066
+
1067
+ Check the value of params against specified validators (true by default)
1068
+
1069
+ `validate_presence`
1070
+
1071
+ Check the params presence against the documentation.
1072
+
1073
+ `validate_key`
1074
+
1075
+ Check the received params to ensure they are defined in the API.
1076
+ (false by default)
1077
+
1078
+ `action_on_non_validated_keys`
1079
+
1080
+ Either `:raise` or `:skip`. If `validate_key` fails, raise error or
1081
+ delete the non-validated key from the params and log the key (`:raise` by default)
1082
+
1083
+ `process_params`
1084
+
1085
+ Process and extract the parameter defined from the params of the
1086
+ request to the api_params variable
1087
+
1088
+ `app_info`
1089
+
1090
+ Application long description.
1091
+
1092
+ `reload_controllers`
1093
+
1094
+ Set to enable/disable reloading controllers (and the documentation
1095
+ with it). Enabled by default in development.
1096
+
1097
+ `api_controllers_matcher`
1098
+
1099
+ For reloading to work properly you need to specify where your API
1100
+ controllers are. Can be an array if multiple paths are needed
1101
+
1102
+ `api_action_matcher`
1103
+
1104
+ Determines the strategy to identity the correct controller action.
1105
+ Needs to be a class that implements a `.call(controller)` method
1106
+
1107
+ `api_routes`
1108
+
1109
+ Set if your application uses a custom API router, different from the
1110
+ Rails default
1111
+
1112
+ `routes_formatter`
1113
+
1114
+ An object providing the translation from the Rails routes to the
1115
+ format usable in the documentation when using the `api!`
1116
+ keyword. By default, the `Apipie::RoutesFormatter` is used.
1117
+
1118
+ `markup`
1119
+
1120
+ You can choose markup language for descriptions of your application,
1121
+ resources and methods. RDoc is the default but you can choose from
1122
+ Apipie::Markup::Markdown.new or Apipie::Markup::Textile.new. In
1123
+ order to use Markdown you need Maruku gem and for Textile you need
1124
+ RedCloth. Add those to your gemfile and run bundle if you want to
1125
+ use them. You can also add any other markup language processor.
1126
+
1127
+ `layout`
1128
+
1129
+ Name of a layout template to use instead of Apipie\'s layout. You
1130
+ can use Apipie.include_stylesheets and Apipie.include_javascripts
1131
+ helpers to include Apipie\'s stylesheets and javascripts.
1132
+
1133
+ `ignored`
1134
+
1135
+ An array of controller names (strings) (might include actions as
1136
+ well) to be ignored when generating the documentation e.g.
1137
+ `%w[Api::CommentsController Api::PostsController#post]`
1138
+
1139
+ `namespaced_resources`
1140
+
1141
+ Use controller paths instead of controller names as resource id.
1142
+ This prevents same named controllers overwriting each other.
1143
+
1144
+ `authenticate`
1145
+
1146
+ Pass a proc in order to authenticate user. Pass nil for no
1147
+ authentication (by default).
1148
+
1149
+ `authorize`
1150
+
1151
+ Pass a proc in order to authorize controllers and methods. The Proc
1152
+ is evaluated in the controller context.
1153
+
1154
+ `show_all_examples`
1155
+
1156
+ Set this to true to set show_in_doc=1 in all recorded examples
1157
+
1158
+ `ignore_allow_blank_false`
1159
+
1160
+ `allow_blank: false` was incorrectly ignored up until
1161
+ version 0.6.0, this bug was fixed in 0.7.0 if you need the old
1162
+ behavior, set this to true
1163
+
1164
+ `link_extension`
1165
+
1166
+ The extension to use for API pages (\'.html\' by default). Link
1167
+ extensions in static API docs cannot be changed from \'.html\'.
1168
+
1169
+ `languages`
1170
+
1171
+ List of languages the API documentation should be translated into.
1172
+ Empty by default.
1173
+
1174
+ `default_locale`
1175
+
1176
+ Locale used for generating documentation when no specific locale is
1177
+ set. Set to \'en\' by default.
1178
+
1179
+ `locale`
1180
+
1181
+ Pass locale setter/getter
1182
+
1183
+ ``` ruby
1184
+ config.locale = lambda { |loc| loc ? FastGettext.set_locale(loc) : FastGettext.locale }
1185
+ ```
1186
+
1187
+ `translate`
1188
+
1189
+ Pass proc to translate strings using the localization library your
1190
+ project uses. For example see [Localization](#localization)
1191
+
1192
+ Example:
1193
+
1194
+ ``` ruby
1195
+ Apipie.configure do |config|
1196
+ config.app_name = "Test app"
1197
+ config.copyright = "&copy; 2012 Pavel Pokorny"
1198
+ config.doc_base_url = "/apidoc"
1199
+ config.api_base_url = "/api"
1200
+ config.validate = false
1201
+ config.markup = Apipie::Markup::Markdown.new
1202
+ config.reload_controllers = Rails.env.development?
1203
+ config.api_controllers_matcher = File.join(Rails.root, "app", "controllers", "**","*.rb")
1204
+ config.api_action_matcher = proc { |controller| controller.params[:action] }
1205
+ config.api_routes = Rails.application.routes
1206
+ config.app_info["1.0"] = "
1207
+ This is where you can inform user about your application and API
1208
+ in general.
1209
+ "
1210
+ config.authenticate = Proc.new do
1211
+ authenticate_or_request_with_http_basic do |username, password|
1212
+ username == "test" && password == "supersecretpassword"
1213
+ end
1214
+ end
1215
+ config.authorize = Proc.new do |controller, method, doc|
1216
+ !method # show all controller doc, but no method docs.
1217
+ end
1218
+ end
1219
+ ```
1220
+
1221
+ `checksum_path`
1222
+
1223
+ Used in ChecksumInHeaders middleware (see [JSON
1224
+ checksums](#json-checksums) for more info). It contains path
1225
+ prefix(es) where the header with checksum is added. If set to nil,
1226
+ checksum is added in headers in every response. e.g.
1227
+ `%w[/api /apipie]`
1228
+
1229
+ `update_checksum`
1230
+
1231
+ If set to `true`, the checksum is recalculated with every
1232
+ documentation_reload call
1233
+
1234
+ # Rails Routes Integration
1235
+
1236
+ Apipie is able to load the information about the paths based on the
1237
+ routes defined in the Rails application, by using the `api!`
1238
+ keyword in the DSL.
1239
+
1240
+ It should be usable out of box, however, one might want to do some
1241
+ customization (such as omitting some implicit parameters in the path
1242
+ etc.). For this kind of customizations one can create a new formatter
1243
+ and pass as the `Apipie.configuration.routes_formatter` option, like
1244
+ this:
1245
+
1246
+ ``` ruby
1247
+ class MyFormatter < Apipie::RoutesFormatter
1248
+ def format_path(route)
1249
+ super.gsub(/\(.*?\)/, '').gsub('//','') # hide all implicit parameters
1250
+ end
1251
+ end
1252
+
1253
+ Apipie.configure do |config|
1254
+ ...
1255
+ config.routes_formatter = MyFormatter.new
1256
+ ...
1257
+ end
1258
+ ```
1259
+
1260
+ A similar way can be used to influence things like order, or a
1261
+ description of the loaded APIs, even omitting some paths if needed.
1262
+
1263
+ # Processing
1264
+
1265
+ The goal is to extract and pre-process parameters of the request.
1266
+
1267
+ For example Rails, by default, transforms an empty array to nil value.
1268
+ Perhaps you want to transform it again into an empty array. Or you want
1269
+ to support an enumeration type (comma separated values) and you want to
1270
+ automatically transform this string into an array.
1271
+
1272
+ To use it, set the `process_params` configuration variable to true.
1273
+
1274
+ Also by using `as` you can separate your API parameter names from the
1275
+ names you are using inside your code.
1276
+
1277
+ To implement it, you just have to write a process_value function in your
1278
+ validator:
1279
+
1280
+ For an enumeration type:
1281
+
1282
+ ``` ruby
1283
+ def process_value(value)
1284
+ value ? value.split(',') : []
1285
+ end
1286
+ ```
1287
+
1288
+ # Validators
1289
+
1290
+ Every parameter needs to have an associated validator. For now there are
1291
+ some basic validators. You can always provide your own to achieve
1292
+ complex results.
1293
+
1294
+ If validations are enabled (default state) the parameters of every
1295
+ request are validated. If the value is wrong an +ArgumentError+
1296
+ exception is raised and can be rescued and processed. It contains a
1297
+ description of the parameter value expectations. Validations can be
1298
+ turned off in the configuration file.
1299
+
1300
+ Here is an example of how to rescue and process a +ParamMissing+ or
1301
+ +ParamInvalid+ error from within the ApplicationController.
1302
+
1303
+ ``` ruby
1304
+ class ApplicationController < ActionController::Base
1305
+
1306
+ # ParamError is superclass of ParamMissing, ParamInvalid
1307
+ rescue_from Apipie::ParamError do |e|
1308
+ render text: e.message, status: :unprocessable_entity
1309
+ end
1310
+
1311
+ # ...
1312
+ end
1313
+ ```
1314
+
1315
+ Parameter validation normally happens after before_actions, just before
1316
+ your controller method is invoked. If you prefer to control when
1317
+ parameter validation occurs, set the configuration parameter `validate`
1318
+ to `:explicitly`. You must then call the `apipie_validations` method
1319
+ yourself, e.g.:
1320
+
1321
+ ``` ruby
1322
+ before_action :apipie_validations
1323
+ ```
1324
+
1325
+ This is useful if you have before_actions which use parameter values:
1326
+ just add them after the `apipie_validations` before_action.
1327
+
1328
+ ## TypeValidator
1329
+
1330
+ Check the parameter type. Only String, Integer, Hash and Array are
1331
+ supported for the sake of simplicity. Read more to find out how to add
1332
+ your own validator.
1333
+
1334
+ ``` ruby
1335
+ param :session, String, :desc => "user is logged in", :required => true
1336
+ param :facts, Hash, :desc => "Additional optional facts about the user"
1337
+ ```
1338
+
1339
+ ## RegexpValidator
1340
+
1341
+ Check parameter value against given regular expression.
1342
+
1343
+ ``` ruby
1344
+ param :regexp_param, /^[0-9]* years/, :desc => "regexp param"
1345
+ ```
1346
+
1347
+ ## EnumValidator
1348
+
1349
+ Check if parameter value is included in the given array.
1350
+
1351
+ ``` ruby
1352
+ param :enum_param, [100, "one", "two", 1, 2], :desc => "enum validator"
1353
+ ```
1354
+
1355
+ ## ProcValidator
1356
+
1357
+ If you need more complex validation and you know you won\'t reuse it,
1358
+ you can use the Proc/lambda validator. Provide your own Proc, taking the
1359
+ value of the parameter as the only argument. Return true if value passes
1360
+ validation or return some text about what is wrong otherwise. Don't
1361
+ use the keyword *return* if you provide an instance of Proc (with lambda
1362
+ it is ok), just use the last statement return property of ruby.
1363
+
1364
+ ``` ruby
1365
+ param :proc_param, lambda { |val|
1366
+ val == "param value" ? true : "The only good value is 'param value'."
1367
+ }, :desc => "proc validator"
1368
+ ```
1369
+
1370
+ ## HashValidator
1371
+
1372
+ You can describe hash parameters in depth if you provide a block with a
1373
+ description of nested values.
1374
+
1375
+ ``` ruby
1376
+ param :user, Hash, :desc => "User info" do
1377
+ param :username, String, :desc => "Username for login", :required => true
1378
+ param :password, String, :desc => "Password for login", :required => true
1379
+ param :membership, ["standard","premium"], :desc => "User membership"
1380
+ end
1381
+ ```
1382
+
1383
+ ## NilValidator
1384
+
1385
+ In fact there isn\'t any NilValidator, but setting it to nil can be used
1386
+ to override parameters described on the resource level.
1387
+
1388
+ ``` ruby
1389
+ param :user, nil
1390
+ def destroy
1391
+ #...
1392
+ end
1393
+ ```
1394
+
1395
+ ## NumberValidator
1396
+
1397
+ Check if the parameter is a positive integer number or zero
1398
+
1399
+ ``` ruby
1400
+ param :product_id, :number, :desc => "Identifier of the product", :required => true
1401
+ param :quantity, :number, :desc => "Number of products to order", :required => true
1402
+ ```
1403
+
1404
+ ## DecimalValidator
1405
+
1406
+ Check if the parameter is a decimal number
1407
+
1408
+ ``` ruby
1409
+ param :latitude, :decimal, :desc => "Geographic latitude", :required => true
1410
+ param :longitude, :decimal, :desc => "Geographic longitude", :required => true
1411
+ ```
1412
+
1413
+ ## ArrayValidator
1414
+
1415
+ Check if the parameter is an array
1416
+
1417
+ Additional options
1418
+
1419
+ `of`
1420
+
1421
+ Specify the type of items. If not given it accepts an array of any item type
1422
+
1423
+ `in`
1424
+
1425
+ Specify an array of valid item values.
1426
+
1427
+ ### Examples
1428
+
1429
+ Assert `things` is an array of any items
1430
+
1431
+ ``` ruby
1432
+ param :things, Array
1433
+ ```
1434
+
1435
+ Assert `hits` must be an array of integer values
1436
+
1437
+ ``` ruby
1438
+ param :hits, Array, of: Integer
1439
+ ```
1440
+
1441
+ Assert `colors` must be an array of valid string values
1442
+
1443
+ ``` ruby
1444
+ param :colors, Array, in: ["red", "green", "blue"]
1445
+ ```
1446
+
1447
+ The retrieving of valid items can be deferred until needed using a
1448
+ lambda. It is evaluated only once
1449
+
1450
+ ``` ruby
1451
+ param :colors, Array, in: -> { Color.all.pluck(:name) }
1452
+ ```
1453
+
1454
+ ### NestedValidator
1455
+
1456
+ You can describe nested parameters in depth if you provide a block with
1457
+ a description of nested values.
1458
+
1459
+ ``` ruby
1460
+ param :comments, Array, :desc => "User comments" do
1461
+ param :name, String, :desc => "Name of the comment", :required => true
1462
+ param :comment, String, :desc => "Full comment", :required => true
1463
+ end
1464
+ ```
1465
+
1466
+ ## Adding custom validator
1467
+
1468
+ Only basic validators are included but it is really easy to add your
1469
+ own. Create a new initializer with a subclass of
1470
+ Apipie::Validator::BaseValidator. Two methods are required to implement
1471
+ this - instance method `validate(value)` and class method
1472
+ `build(param_description, argument, options, block)`.
1473
+
1474
+ When searching for the validator +build+ method, every subclass of
1475
+ Apipie::Validator::BaseValidator is called. The first one that returns
1476
+ the constructed validator object is used.
1477
+
1478
+ Example: Adding IntegerValidator
1479
+
1480
+ We want to check if the parameter value is an integer like this:
1481
+
1482
+ ``` ruby
1483
+ param :id, Integer, :desc => "Company ID"
1484
+ ```
1485
+
1486
+ So we create apipie_validators.rb initializer with this content:
1487
+
1488
+ ``` ruby
1489
+ class IntegerValidator < Apipie::Validator::BaseValidator
1490
+
1491
+ def initialize(param_description, argument)
1492
+ super(param_description)
1493
+ @type = argument
1494
+ end
1495
+
1496
+ def validate(value)
1497
+ return false if value.nil?
1498
+ !!(value.to_s =~ /^[-+]?[0-9]+$/)
1499
+ end
1500
+
1501
+ def self.build(param_description, argument, options, block)
1502
+ if argument == Integer
1503
+ self.new(param_description, argument)
1504
+ end
1505
+ end
1506
+
1507
+ def description
1508
+ "Must be #{@type}."
1509
+ end
1510
+
1511
+ def expected_type
1512
+ 'numeric'
1513
+ end
1514
+ end
1515
+ ```
1516
+
1517
+ Parameters of the build method:
1518
+
1519
+ `param_description`
1520
+
1521
+ Instance of Apipie::ParamDescription contains all given information about the validated parameter.
1522
+
1523
+ `argument`
1524
+
1525
+ Specified validator; in our example it is +Integer+
1526
+
1527
+ `options`
1528
+
1529
+ Hash with specified options, for us just `{:desc => "Company ID"}`
1530
+
1531
+ `block`
1532
+
1533
+ Block converted into Proc, use it as you desire. In this example nil.
1534
+
1535
+ If your validator includes valid values that respond true to
1536
+ `.blank?`, you should also define:
1537
+
1538
+ ``` ruby
1539
+ def ignore_allow_blank?
1540
+ true
1541
+ end
1542
+ ```
1543
+
1544
+ so that the validation does not fail for valid values.
1545
+
1546
+ # Versioning
1547
+
1548
+ Every resource/method can belong to one or more versions. The version is
1549
+ specified with the `api_version` DSL keyword. When not
1550
+ specified, the resource belongs to `config.default_version`
1551
+ (\"1.0\" by default)
1552
+
1553
+ ``` ruby
1554
+ resource_description do
1555
+ api_versions "1", "2"
1556
+ end
1557
+
1558
+ api :GET, "/api/users/", "List: users"
1559
+ api_version "1"
1560
+ def index
1561
+ # ...
1562
+ end
1563
+
1564
+ api :GET, "/api/users/", "List: users", :deprecated => true
1565
+ ```
1566
+
1567
+ In the example above we say the whole controller/resource is defined for
1568
+ versions \"1\" and \"2\", but we override this by explicitly saying
1569
+ `index` belongs only to version \"1\". Also, inheritance
1570
+ works (therefore we can specify the api_version for the parent
1571
+ controller, and all children will know about that). Routes can be
1572
+ flagged as deprecated, and an annotation will be added to them when
1573
+ viewing in the API documentation.
1574
+
1575
+ From the Apipie API perspective, the resources belong to the version.
1576
+ With versioning, there are paths like this provided by apipie:
1577
+
1578
+ ```
1579
+ /apipie/1/users/index
1580
+ /apipie/2/users/index
1581
+ ```
1582
+
1583
+ When not specifying the version explicitly in the path (or in DSL),
1584
+ default version (`Apipie.configuration.default_version`) is
1585
+ used instead (\"1.0\" by default). Therefore, an application that
1586
+ doesn\'t need versioning should work as before.
1587
+
1588
+ The static page generator takes a version parameter (or uses default).
1589
+
1590
+ You can specify the versions for the examples, with the
1591
+ `versions` keyword. It specifies the versions the example is
1592
+ used for. When not specified, it\'s shown in all versions with the given
1593
+ method.
1594
+
1595
+ When referencing or querying the resource/method descripion, this format
1596
+ should be used: \"version#resource#method\". When not specified, the
1597
+ default version is used instead.
1598
+
1599
+ # Markup
1600
+
1601
+ The default markup language is
1602
+ [RDoc](https://ruby.github.io/rdoc/RDoc/Markup.html). It can be changed
1603
+ in the config file (`config.markup=`) to one of these:
1604
+
1605
+ Markdown
1606
+
1607
+ Use Apipie::Markup::Markdown.new. You need Maruku gem.
1608
+
1609
+ Textile
1610
+
1611
+ Use Apipie::Markup::Textile.new. You need RedCloth gem.
1612
+
1613
+ Or provide you own object with a `to_html(text)` method. For
1614
+ inspiration, this is how Textile markup usage is implemented:
1615
+
1616
+ ``` ruby
1617
+ class Textile
1618
+ def initialize
1619
+ require 'RedCloth'
1620
+ end
1621
+ def to_html(text)
1622
+ RedCloth.new(text).to_html
1623
+ end
1624
+ end
1625
+ ```
1626
+
1627
+ # Localization
1628
+
1629
+ Apipie has support for localized API documentation in both formats (JSON
1630
+ and HTML). Apipie uses the library I18n for localization of itself.
1631
+ Check `config/locales` directory for available translations.
1632
+
1633
+ A major part of strings in the documentation comes from the API. As
1634
+ preferences regarding localization libraries differ amongst project,
1635
+ Apipie needs to know how to set the locale for your project, and how to
1636
+ translate a string using the library your project uses. That can be done
1637
+ using lambdas in configuration.
1638
+
1639
+ Sample configuration when your project uses FastGettext
1640
+
1641
+ ``` ruby
1642
+ Apipie.configure do |config|
1643
+ ...
1644
+ config.languages = ['en', 'cs']
1645
+ config.default_locale = 'en'
1646
+ config.locale = lambda { |loc| loc ? FastGettext.set_locale(loc) : FastGettext.locale }
1647
+ config.translate = lambda do |str, loc|
1648
+ old_loc = FastGettext.locale
1649
+ FastGettext.set_locale(loc)
1650
+ trans = _(str)
1651
+ FastGettext.set_locale(old_loc)
1652
+ trans
1653
+ end
1654
+ end
1655
+ ```
1656
+
1657
+ And the strings in the API documentation need to be marked with the
1658
+ `N_()` function
1659
+
1660
+ ``` ruby
1661
+ api :GET, "/users/:id", N_("Show user profile")
1662
+ param :session, String, :desc => N_("user is logged in"), :required => true
1663
+ ```
1664
+
1665
+ When your project use I18n, localization related configuration could
1666
+ appear as follows
1667
+
1668
+ ``` ruby
1669
+ Apipie.configure do |config|
1670
+ ...
1671
+ config.languages = ['en', 'cs']
1672
+ config.default_locale = 'en'
1673
+ config.locale = lambda { |loc| loc ? I18n.locale = loc : I18n.locale }
1674
+ config.translate = lambda do |str, loc|
1675
+ return '' if str.blank?
1676
+ I18n.t str, locale: loc, scope: 'doc'
1677
+ end
1678
+ end
1679
+ ```
1680
+
1681
+ And the strings in the API documentation needs to be in the form of
1682
+ translation keys
1683
+
1684
+ ``` ruby
1685
+ api :GET, "/users/:id", "show_user_profile"
1686
+ param :session, String, :desc => "user_is_logged_in", :required => true
1687
+ ```
1688
+
1689
+ The localized versions of the documentation are distinguished by
1690
+ language in the filename. E.g. `doc/apidoc/apidoc.cs.html` is static
1691
+ documentation in the Czech language. If the language is missing, e.g.
1692
+ `doc/apidoc/apidoc.html`, the documentation is localized with the
1693
+ `default_locale`.
1694
+
1695
+ The dynamic documentation follows the same schema. The
1696
+ `http://localhost:3000/apidoc/v1.cs.html` is documentation for version
1697
+ \'1\' of the API in the Czech language. For JSON descriptions, the API
1698
+ applies the same format: `http://localhost:3000/apidoc/v1.cs.json`
1699
+
1700
+ # Modifying Views
1701
+
1702
+ To modify the views of your documentation, run `rails g apipie:views`.
1703
+ This will copy the Apipie views to `app/views/apipie/apipies` and
1704
+ `app/views/layouts/apipie`.
1705
+
1706
+ # Static files
1707
+
1708
+ To generate a static version of documentation (perhaps to put it on your
1709
+ project site or something), run the `rake apipie:static` task. It will
1710
+ create a set of HTML files (multi-pages, single-page, plain) in your doc
1711
+ directory. If you prefer a JSON version run `rake apipie:static_json`.
1712
+ By default the documentation for the default API version is used. You
1713
+ can specify the version with `rake apipie:static[2.0]`
1714
+
1715
+ When you want to avoid any unnecessary computation in production mode,
1716
+ you can generate a cache with `rake apipie:cache` and configure the app
1717
+ to use it in production with `config.use_cache = Rails.env.production?`
1718
+
1719
+ Default cache dir is `File.join(Rails.root, "public", "apipie-cache")`,
1720
+ you can change it to where you want, example:
1721
+ `config.cache_dir = File.join(Rails.root, "doc", "apidoc")`.
1722
+
1723
+ If, for some complex cases, you need to generate/re-generate just part
1724
+ of the cache use `rake apipie:cache cache_part=index` resp.
1725
+ `rake apipie:cache cache_part=resources` To generate it for different
1726
+ locations for further processing use
1727
+ `rake apipie:cache OUT=/tmp/apipie_cache`.
1728
+
1729
+ # Static Swagger (OpenAPI 2.0) files
1730
+
1731
+ To generate a static Swagger definition file from the api, run
1732
+ `rake apipie:static_swagger_json`. By default the documentation for the
1733
+ default API version is used. You can specify the version with
1734
+ `rake apipie:static_swagger_json[2.0]`. A swagger file will be generated
1735
+ for each locale. The files will be generated in the same location as the
1736
+ static_json files, but instead of being named
1737
+ `schema_apipie[.locale].json`, they will be called
1738
+ `schema_swagger[.locale].json`.
1739
+
1740
+ ## Specifying default values for parameters
1741
+
1742
+ Swagger allows method definitions to include an indication of the the
1743
+ default value for each parameter. To include such indications, use
1744
+ `:default_value => <some value>` in the parameter definition DSL. For
1745
+ example:
1746
+
1747
+ ``` ruby
1748
+ param :do_something, Boolean, :desc => "take an action", :required => false, :default_value => false
1749
+ ```
1750
+
1751
+ ## Generated Warnings
1752
+
1753
+ The help identify potential improvements to your documentation, the
1754
+ swagger generation process issues warnings if it identifies various
1755
+ shortcomings of the DSL documentation. Each warning has a code to allow
1756
+ selective suppression (see swagger-specific configuration below)
1757
+
1758
+ | Error Code | Description |
1759
+ |------------|-------------------------------------------------------------------------------------|
1760
+ | 100 | Missing short description for method |
1761
+ | 101 | Added missing / at beginning of path |
1762
+ | 102 | No return codes specified for method |
1763
+ | 103 | A parameter is a generic Hash without an internal type specification |
1764
+ | 104 | A parameter is an 'in-path' parameter, but specified as 'not required' in the DSL |
1765
+ | 105 | A parameter is optional but does not have a default value specified |
1766
+ | 106 | A parameter was omitted from the swagger output because it is a Hash without fields in a formData specification |
1767
+ | 107 | A path parameter is not described |
1768
+ | 108 | Inferring that a parameter type is boolean because described as an enum with `[false true]` values |
1769
+
1770
+
1771
+ ## Swagger-Specific Configuration Parameters
1772
+
1773
+ There are several configuration parameters that determine the structure
1774
+ of the generated swagger file:
1775
+
1776
+ `config.generator.swagger.content_type_input`
1777
+
1778
+ - If the value is `:form_data` - the swagger file will indicate that
1779
+ the server consumes the content types
1780
+ `application/x-www-form-urlencoded` and `multipart/form-data`.
1781
+ Non-path parameters will have the value `"in": "formData"`. Note
1782
+ that parameters of type Hash that do not have any fields in them
1783
+ will *be omitted* from the resulting files, as there is no way to
1784
+ describe them in swagger.
1785
+
1786
+ - If the value is `:json` - the swagger file will indicate that the
1787
+ server consumes the content type `application/json`. All non-path
1788
+ parameters will be included in the schema of a single `"in": "body"`
1789
+ parameter of type `object`.
1790
+
1791
+ - You can specify the value of this configuration parameter as an
1792
+ additional input to the rake command (e.g.,
1793
+ `rake apipie:static_swagger_json[2.0,form_data]`).
1794
+
1795
+ `config.generator.swagger.json_input_uses_refs`
1796
+
1797
+ - This parameter is only relevant if `swagger.content_type_input` is
1798
+ `:json`.
1799
+
1800
+ - If `true`: the schema of the `"in": "body"` parameter of each method
1801
+ is given its own entry in the `definitions` section, and is
1802
+ referenced using `$ref` from the method definition.
1803
+
1804
+ - If `false`: the body parameter definitions are inlined within the
1805
+ method definitions.
1806
+
1807
+ `config.generator.swagger.include_warning_tags`
1808
+
1809
+ - If `true`: in addition to tagging methods with the name of the
1810
+ resource they belong to, methods for which warnings have been issued
1811
+ will be tagged with.
1812
+
1813
+ `config.generator.swagger.suppress_warnings`
1814
+
1815
+ - If `false`: no warnings will be suppressed
1816
+
1817
+ - If `true`: all warnings will be suppressed
1818
+
1819
+ - If an array of values (e.g., `[100,102,107]`), only the warnings
1820
+ identified by the numbers in the array will be suppressed.
1821
+
1822
+ `config.generator.swagger.api_host`
1823
+
1824
+ - The value to place in the swagger host field. Default is `localhost:3000`
1825
+ - If `nil` then then host field will not be included.
1826
+
1827
+ `config.generator.swagger.allow_additional_properties_in_response`
1828
+
1829
+ - If `false` (default): response descriptions in the generated swagger
1830
+ will include an `additional-properties: false` field
1831
+
1832
+ - If `true`: the `additional-properties: false` field will not be
1833
+ included in response object descriptions
1834
+
1835
+ `config.generator.swagger.schemes`
1836
+
1837
+ - An array of transport schemes that the API supports. This can
1838
+ include any combination of `http`, `https`, `ws` and `wss`. By
1839
+ default to encourage good security practices, `['https']` is
1840
+ specified.
1841
+
1842
+ `config:swagger.security_definitions`
1843
+
1844
+ - If the API requires authentication, you can specify details of the
1845
+ authentication mechanisms supported as a (Hash) value here. See
1846
+ \[<https://swagger.io/docs/specification/2-0/authentication/>\] for
1847
+ details of what values can be specified By default, no security is
1848
+ defined.
1849
+
1850
+ `config.generator.swagger.global_security`
1851
+
1852
+ - If the API requires authentication, you can specify which of the
1853
+ authentication mechanisms are supported by all API operations as an
1854
+ Array of hashes here. This should be used in conjunction with the
1855
+ mechanisms defined by `swagger.security_definitions`. See
1856
+ \[<https://swagger.io/docs/specification/2-0/authentication/>\] for
1857
+ details of what values can be specified By default, no security is
1858
+ defined.
1859
+
1860
+ `config.generator.swagger.skip_default_tags`
1861
+
1862
+ - By setting `false` (default): The resource name for e.g.
1863
+ `/pets/{petId}` will automatically be added as a tag `pets`. By
1864
+ setting `true`: The tags needs to be explicitly added to the
1865
+ resource using the DSL.
1866
+
1867
+ ## Known limitations of the current implementation
1868
+
1869
+ - There is currently no way to document the structure and content-type
1870
+ of the data returned from a method
1871
+ - Recorded examples are currently not included in the generated
1872
+ swagger file
1873
+ - The apipie `formats` value is ignored.
1874
+ - It is not possible to specify the \"consumed\" content type on a
1875
+ per-method basis
1876
+ - It is not possible to leverage all of the parameter type/format
1877
+ capabilities of swagger
1878
+ - Only OpenAPI 2.0 is supported
1879
+ - Responses are defined inline and not as a \$ref
1880
+ - It is not possible to specify per-operation security requirements
1881
+ (only global)
1882
+
1883
+ # Dynamic Swagger generation
1884
+
1885
+ To generate swagger dynamically, use
1886
+ `http://localhost:3000/apipie.json?type=swagger`.
1887
+
1888
+ Note that authorization is not supported for dynamic swagger generation,
1889
+ so if `config.authorize` is defined, dynamic swagger generation will be
1890
+ disabled.
1891
+
1892
+ Dynamically generated swagger is not cached, and is always generated on
1893
+ the fly.
1894
+
1895
+ # JSON checksums
1896
+
1897
+ If the API client needs to be sure that the JSON didn\'t changed, add
1898
+ the `ApipieChecksumInHeaders` middleware in your rails app. It can add a
1899
+ checksum of the entire JSON document in the response headers.
1900
+
1901
+ ```
1902
+ "Apipie-Checksum"=>"fb81460e7f4e78d059f826624bdf9504"
1903
+ ```
1904
+
1905
+ [Apipie bindings](https://github.com/Apipie/apipie-bindings) uses this
1906
+ feature to refresh its JSON cache.
1907
+
1908
+ To set it up add the following to your `application.rb`
1909
+
1910
+ ```
1911
+ require 'apipie/middleware/checksum_in_headers'
1912
+ # Add JSON checksum in headers for smarter caching
1913
+ config.middleware.use "Apipie::Middleware::ChecksumInHeaders"
1914
+ ```
1915
+
1916
+ And in your apipie initializer allow checksum calculation
1917
+
1918
+ ```
1919
+ Apipie.configuration.update_checksum = true
1920
+ ```
1921
+
1922
+ By default the header is added to responses for `config.doc_base_url`
1923
+ and `/api`. It can be changed in configuration (see [Configuration
1924
+ Reference](#configuration-reference) for details).
1925
+
1926
+ The checksum calculation is lazy, and done with the first request. If
1927
+ you run with `use_cache = true`, do not forget to run the rake task
1928
+ `apipie:cache`.
1929
+
1930
+ # Tests Integration
1931
+
1932
+ Apipie integrates with automated testing in two ways. *Documentation
1933
+ bootstrapping* and *examples recording*.
1934
+
1935
+ ## Documentation Bootstrapping
1936
+
1937
+ Let\'s say you have an application without REST API documentation.
1938
+ However you have a set of tests that are run against this API. A lot of
1939
+ information is already included in these tests, it just needs to be
1940
+ extracted somehow. Luckily, Apipie provides such a feature.
1941
+
1942
+ When running the tests, set the `APIPIE_RECORD=params` environment
1943
+ variable or call `Apipie.record('params')` from specs starter. You can
1944
+ either use it with functional tests:
1945
+
1946
+ ```
1947
+ APIPIE_RECORD=params rake test:functionals
1948
+ ```
1949
+
1950
+ or you can run your server with this param, in case you run the tests
1951
+ against running server:
1952
+
1953
+ ```
1954
+ APIPIE_RECORD=params rails server
1955
+ ```
1956
+
1957
+ When the process quits, the data from requests/responses are used to
1958
+ determine the documentation. It\'s quite raw, but it makes the initial
1959
+ phase much easier.
1960
+
1961
+ ## Examples Recording
1962
+
1963
+ You can also use the tests to generate up-to-date examples for your
1964
+ code. Similar to the bootstrapping process, you can use it with
1965
+ functional tests or a running server, setting `APIPIE_RECORD=examples`
1966
+ or calling `Apipie.record('examples')` in your specs starter.
1967
+
1968
+ ```
1969
+ APIPIE_RECORD=examples rake test:functionals
1970
+ APIPIE_RECORD=examples rails server
1971
+ ```
1972
+
1973
+ The data is written into `doc/apipie_examples.yml`. By default, only the
1974
+ first example is shown for each action. You can customize this by
1975
+ setting the `show_in_doc` attribute at each example.
1976
+
1977
+ You can add a title to the examples (useful when showing more than one
1978
+ example per method) by adding a \'title\' attribute.
1979
+
1980
+ ```
1981
+ --- !omap
1982
+ - announcements#index:
1983
+ - !omap
1984
+ - title: This is a custom title for this example
1985
+ - verb: :GET
1986
+ - path: /api/blabla/1
1987
+ - versions:
1988
+ - '1.0'
1989
+ - query:
1990
+ - request_data:
1991
+ - response_data:
1992
+ ...
1993
+ - code: 200
1994
+ - show_in_doc: 1 # If 1, show. If 0, do not show.
1995
+ - recorded: true
1996
+ ```
1997
+
1998
+ In RSpec you can add metadata to examples. We can use that feature to
1999
+ mark selected examples - the ones that perform the requests that we want
2000
+ to show as examples in the documentation.
2001
+
2002
+ For example, we can add `show_in_doc` to examples, like this:
2003
+
2004
+ ``` ruby
2005
+ describe "This is the correct path" do
2006
+ it "some test", :show_in_doc do
2007
+ ....
2008
+ end
2009
+ end
2010
+
2011
+ context "These are edge cases" do
2012
+ it "Can't authenticate" do
2013
+ ....
2014
+ end
2015
+
2016
+ it "record not found" do
2017
+ ....
2018
+ end
2019
+ end
2020
+ ```
2021
+
2022
+ And then configure RSpec in this way:
2023
+
2024
+ ``` ruby
2025
+ RSpec.configure do |config|
2026
+ config.treat_symbols_as_metadata_keys_with_true_values = true
2027
+ config.filter_run :show_in_doc => true if ENV['APIPIE_RECORD']
2028
+ end
2029
+ ```
2030
+
2031
+ This way, when running in recording mode, only the tests that have been
2032
+ marked with the `:show_in_doc` metadata will be run, and hence only
2033
+ those will be used as examples.
2034
+
2035
+ ## Caveats
2036
+
2037
+ Make sure to enable `config.render_views` in your
2038
+ `config/rails_helper.rb` or `config/spec_helper.rb` if you\'re using
2039
+ jbuilder, or you will get back empty results
2040
+
2041
+ # Bindings Generator
2042
+
2043
+ In earlier versions (\<= 0.0.13), there was a simple client generator as
2044
+ a part of Apipie gem. As more features and users came to Apipie, there
2045
+ was a greater need for changes on a per project basis. It\'s hard (or
2046
+ even impossible) to provide a generic solution for the client code. We
2047
+ also don\'t want to tell you what\'s the right way to do it (what gems
2048
+ to use, how the API should look like etc.).
2049
+
2050
+ Therefore you can\'t generate client code directly by a rake task in
2051
+ further versions.
2052
+
2053
+ There is, however, an even better and more flexible way to reuse your
2054
+ API documentation for this purpose: using the API the Apipie provides in
2055
+ the generator code. Check out our sister project
2056
+ [apipie-bindings](https://github.com/Apipie/apipie-bindings), as they
2057
+ use exactly this approach. You also don\'t need to run the service,
2058
+ provided it uses Apipie as a backend.
2059
+
2060
+ And if you write one on your own, don\'t hesitate to share it with us!
2061
+
2062
+ # Contributing
2063
+
2064
+ Then, you can install dependencies and run the test suite:
2065
+
2066
+ ``` shell
2067
+ > bundle install
2068
+ > bundle exec rspec
2069
+ ```
2070
+
2071
+ # Disqus Integration
2072
+
2073
+ You can setup [Disqus](https://disqus.com/) discussion within your
2074
+ documentation. Just set the credentials in the Apipie configuration:
2075
+
2076
+ ``` ruby
2077
+ config.disqus_shortname = "MyProjectDoc"
2078
+ ```
2079
+
2080
+ # External References
2081
+
2082
+ - [Getting started tutorial](https://github.com/iNecas/apipie-demo)
2083
+ -including examples of using the tests integration and versioning.
2084
+ - [Real-world application usage](https://github.com/Katello/katello)
2085
+ - [Read-world application usage with
2086
+ versioning](https://github.com/theforeman/foreman)
2087
+ - [Using Apipie API to generate
2088
+ bindings](https://github.com/Apipie/apipie-bindings)