apipie-rails 0.3.6 → 0.5.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +23 -7
  3. data/CHANGELOG.md +147 -2
  4. data/Gemfile +1 -0
  5. data/Gemfile.rails41 +2 -0
  6. data/Gemfile.rails42 +10 -1
  7. data/Gemfile.rails50 +9 -0
  8. data/Gemfile.rails51 +9 -0
  9. data/Gemfile.rails60 +14 -0
  10. data/PROPOSAL_FOR_RESPONSE_DESCRIPTIONS.md +244 -0
  11. data/README.rst +570 -17
  12. data/apipie-rails.gemspec +3 -3
  13. data/app/controllers/apipie/apipies_controller.rb +48 -17
  14. data/app/views/apipie/apipies/_method_detail.erb +21 -0
  15. data/app/views/apipie/apipies/_params.html.erb +4 -2
  16. data/app/views/apipie/apipies/index.html.erb +5 -1
  17. data/app/views/apipie/apipies/resource.html.erb +3 -0
  18. data/app/views/layouts/apipie/apipie.html.erb +1 -1
  19. data/config/locales/en.yml +1 -0
  20. data/config/locales/fr.yml +31 -0
  21. data/config/locales/it.yml +31 -0
  22. data/config/locales/ja.yml +31 -0
  23. data/lib/apipie/apipie_module.rb +22 -4
  24. data/lib/apipie/application.rb +55 -28
  25. data/lib/apipie/configuration.rb +19 -3
  26. data/lib/apipie/core_ext/route.rb +9 -0
  27. data/lib/apipie/dsl_definition.rb +151 -10
  28. data/lib/apipie/error_description.rb +9 -2
  29. data/lib/apipie/errors.rb +34 -0
  30. data/lib/apipie/extractor/collector.rb +4 -0
  31. data/lib/apipie/extractor/recorder.rb +13 -12
  32. data/lib/apipie/extractor/writer.rb +83 -55
  33. data/lib/apipie/extractor.rb +10 -4
  34. data/lib/apipie/method_description.rb +51 -4
  35. data/lib/apipie/param_description.rb +56 -2
  36. data/lib/apipie/resource_description.rb +10 -3
  37. data/lib/apipie/response_description.rb +131 -0
  38. data/lib/apipie/response_description_adapter.rb +200 -0
  39. data/lib/apipie/routes_formatter.rb +1 -1
  40. data/lib/apipie/rspec/response_validation_helper.rb +194 -0
  41. data/lib/apipie/static_dispatcher.rb +3 -2
  42. data/lib/apipie/swagger_generator.rb +708 -0
  43. data/lib/apipie/tag_list_description.rb +11 -0
  44. data/lib/apipie/validator.rb +69 -8
  45. data/lib/apipie/version.rb +1 -1
  46. data/lib/apipie-rails.rb +7 -0
  47. data/lib/tasks/apipie.rake +103 -8
  48. data/spec/controllers/apipies_controller_spec.rb +52 -12
  49. data/spec/controllers/concerns_controller_spec.rb +2 -2
  50. data/spec/controllers/extended_controller_spec.rb +14 -0
  51. data/spec/controllers/memes_controller_spec.rb +10 -0
  52. data/spec/controllers/users_controller_spec.rb +115 -75
  53. data/spec/dummy/app/controllers/application_controller.rb +5 -1
  54. data/spec/dummy/app/controllers/concerns/extending_concern.rb +12 -0
  55. data/spec/dummy/app/controllers/concerns/sample_controller.rb +5 -5
  56. data/spec/dummy/app/controllers/extended_controller.rb +14 -0
  57. data/spec/dummy/app/controllers/pets_controller.rb +408 -0
  58. data/spec/dummy/app/controllers/pets_using_auto_views_controller.rb +73 -0
  59. data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +95 -0
  60. data/spec/dummy/app/controllers/tagged_cats_controller.rb +32 -0
  61. data/spec/dummy/app/controllers/tagged_dogs_controller.rb +15 -0
  62. data/spec/dummy/app/controllers/twitter_example_controller.rb +5 -0
  63. data/spec/dummy/app/controllers/users_controller.rb +19 -11
  64. data/spec/dummy/components/test_engine/Gemfile +6 -0
  65. data/spec/dummy/components/test_engine/app/controllers/test_engine/application_controller.rb +4 -0
  66. data/spec/dummy/components/test_engine/app/controllers/test_engine/memes_controller.rb +37 -0
  67. data/spec/dummy/components/test_engine/config/routes.rb +3 -0
  68. data/spec/dummy/components/test_engine/db/.gitkeep +0 -0
  69. data/spec/dummy/components/test_engine/lib/test_engine.rb +7 -0
  70. data/spec/dummy/components/test_engine/test_engine.gemspec +11 -0
  71. data/spec/dummy/config/application.rb +5 -0
  72. data/spec/dummy/config/environments/development.rb +3 -0
  73. data/spec/dummy/config/environments/production.rb +3 -0
  74. data/spec/dummy/config/environments/test.rb +3 -0
  75. data/spec/dummy/config/initializers/apipie.rb +3 -1
  76. data/spec/dummy/config/routes.rb +24 -1
  77. data/spec/lib/extractor/writer_spec.rb +32 -4
  78. data/spec/lib/file_handler_spec.rb +18 -0
  79. data/spec/lib/method_description_spec.rb +34 -0
  80. data/spec/lib/swagger/openapi_2_0_schema.json +1607 -0
  81. data/spec/lib/swagger/rake_swagger_spec.rb +139 -0
  82. data/spec/lib/swagger/response_validation_spec.rb +104 -0
  83. data/spec/lib/swagger/swagger_dsl_spec.rb +658 -0
  84. data/spec/lib/validator_spec.rb +58 -0
  85. data/spec/lib/validators/array_validator_spec.rb +28 -8
  86. data/spec/spec_helper.rb +68 -0
  87. metadata +75 -23
  88. data/Gemfile +0 -7
  89. data/Gemfile.rails32 +0 -6
  90. data/Gemfile.rails40 +0 -5
  91. data/lib/apipie/client/generator.rb +0 -135
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5d6fc12663b63923153a8f238fac0c7556257aeb
4
- data.tar.gz: 2271e183d1319d0d42df3d909285d7ded70970aa
2
+ SHA256:
3
+ metadata.gz: 855ada05457368ea7521d46865242c73a15c33a33546d7b0dac1d2b90d779c70
4
+ data.tar.gz: 0cc30d4f4a38a476cab6ed92b6a4a00c45bd2036c8b35fb8373fbb215fb2ea80
5
5
  SHA512:
6
- metadata.gz: 7864fe236a067ce5a0a3068a51d01a53b641ade349f6f5dc8b2d9ebc242e8c078de8601d82e62c4560770e9c537bfe98771e1f24c4b693fb31cb5fc32148d91d
7
- data.tar.gz: fb902c9fc943fb6f3067576af5db940b015009810d908ccb02d684e9364e9cb293dc257d73848c7fee42cf356ad9756189734e0e5811e8f3ee07083535f483c2
6
+ metadata.gz: 9b0ba79aee65ed21249fa35336166783697719fabc74831816513ea1d0b91162bde342b51fad08121ea38c27f5015bbf196ac524049dcbbc8635dd0a57f13cff
7
+ data.tar.gz: 0f9f593ee579dba0baf16175e8c9d916dd370eba6a5c37cee4df2a92dea1efe0ea936b2444597274dd327244063000bb3a9cff454413956cd98bd27c5652afc6
data/.travis.yml CHANGED
@@ -1,12 +1,28 @@
1
1
  language: ruby
2
2
  sudo: false
3
+ before_install: >-
4
+ if ruby -v | grep 'ruby 2.2'; then
5
+ gem install bundler -v '~> 1.17'
6
+ fi
3
7
  rvm:
4
- - 1.9.3
5
- - 2.0.0
6
- - 2.1.7
7
- - 2.2.3
8
+ - 2.2.10
9
+ - 2.3.8
10
+ - 2.4.5
11
+ - 2.5.3
12
+ - 2.6.0
8
13
  gemfile:
9
- - Gemfile.rails32
10
- - Gemfile.rails40
11
- - Gemfile.rails41
12
14
  - Gemfile.rails42
15
+ - Gemfile.rails51 # Min ruby 2.2.2
16
+ - Gemfile.rails60 # Min ruby 2.5.0
17
+ matrix:
18
+ exclude:
19
+ - rvm: 2.5.3
20
+ gemfile: Gemfile.rails42
21
+ - rvm: 2.6.0
22
+ gemfile: Gemfile.rails42
23
+ - rvm: 2.2.10
24
+ gemfile: Gemfile.rails60
25
+ - rvm: 2.3.8
26
+ gemfile: Gemfile.rails60
27
+ - rvm: 2.4.5
28
+ gemfile: Gemfile.rails60
data/CHANGELOG.md CHANGED
@@ -1,7 +1,152 @@
1
- ===========
2
1
  Changelog
3
2
  ===========
4
3
 
4
+ [v0.5.17](https://github.com/Apipie/apipie-rails/tree/v0.5.17) (2020-01-20)
5
+ --------
6
+
7
+ [Full Changelog](https://github.com/Apipie/apipie-rails/compare/v0.5.16...v0.5.17)
8
+
9
+ - Allows update metadata for methods [\#667](https://github.com/Apipie/apipie-rails/pull/667) ([speckins](https://github.com/speckins))
10
+
11
+ [v0.5.16](https://github.com/Apipie/apipie-rails/tree/v0.5.16) (2019-05-22)
12
+ --------
13
+
14
+ [Full Changelog](https://github.com/Apipie/apipie-rails/compare/v0.5.15...v0.5.16)
15
+
16
+ - Load file directly instead of using Rails constant [\#665](https://github.com/Apipie/apipie-rails/pull/665) ([speckins](https://github.com/speckins))
17
+
18
+ [v0.5.15](https://github.com/Apipie/apipie-rails/tree/v0.5.15) (2019-01-03)
19
+ --------
20
+ [Full Changelog](https://github.com/Apipie/apipie-rails/compare/v0.5.14...v0.5.15)
21
+
22
+
23
+ - Fix authorization of resources [\#655](https://github.com/Apipie/apipie-rails/pull/655) ([NielsKSchjoedt](https://github.com/NielsKSchjoedt))
24
+ - Use configured value when swagger\_content\_type\_input argument is not passed [\#648](https://github.com/Apipie/apipie-rails/pull/648) ([nullnull](https://github.com/nullnull))
25
+ - Fix "ArgumentError: string contains null byte" on malformed stings [\#477](https://github.com/Apipie/apipie-rails/pull/477) ([avokhmin](https://github.com/avokhmin))
26
+
27
+ v0.5.14
28
+ -------
29
+ - HTML escape validator values [\#645](https://github.com/Apipie/apipie-rails/pull/645) ([ekohl](https://github.com/ekohl))
30
+ - Support for adding new params via `update\_api` [\#642](https://github.com/Apipie/apipie-rails/pull/642) ([iNecas](https://github.com/iNecas))
31
+ - Allow the "null" JSON string to be used as a parameter in Apipie spec examples \(`show\_in\_doc`\) [\#641](https://github.com/Apipie/apipie-rails/pull/641) ([enrique-guillen](https://github.com/enrique-guillen))
32
+ - Fix examples recording for specific cases [\#640](https://github.com/Apipie/apipie-rails/pull/640) ([Marri](https://github.com/Marri))
33
+ - Add description section to response [\#639](https://github.com/Apipie/apipie-rails/pull/639) ([X1ting](https://github.com/X1ting))
34
+
35
+
36
+ v0.5.13
37
+ -------
38
+ - Fix swagger generation if a controller's parent doesn't define a resource_description [\#637](https://github.com/Apipie/apipie-rails/pull/637) ([enrique-guillen](https://github.com/enrique-guillen))
39
+
40
+ v0.5.12
41
+ -------
42
+ - Fix returns displaying [\#635](https://github.com/Apipie/apipie-rails/pull/635) ([X1ting](https://github.com/X1ting))
43
+
44
+ v0.5.11
45
+ -------
46
+
47
+ - Adds swagger tags in swagger output [\#634](https://github.com/Apipie/apipie-rails/pull/634) ([enrique-guillen](https://github.com/enrique-guillen))
48
+ - Generate swagger with headers [\#630](https://github.com/Apipie/apipie-rails/pull/630) ([Uysim](https://github.com/Uysim))
49
+ - Fix examples not being generated for Rails < 5.0.0 [\#633](https://github.com/Apipie/apipie-rails/pull/633) ([RomanKapitonov](https://github.com/RomanKapitonov))
50
+
51
+ v0.5.10
52
+ ------
53
+
54
+ - Support response validation [\#626](https://github.com/Apipie/apipie-rails/pull/626) ([COzero](https://github.com/COzero))
55
+
56
+ v0.5.9
57
+ ------
58
+
59
+ - Support response validation [\#619](https://github.com/Apipie/apipie-rails/pull/619) ([abenari](https://github.com/abenari))
60
+ - Expect :number to have type 'numeric' [\#614](https://github.com/Apipie/apipie-rails/pull/614) ([akofink](https://github.com/akofink))
61
+ - New validator - DecimalValidator [\#431](https://github.com/Apipie/apipie-rails/pull/431) ([kiddrew](https://github.com/kiddrew))
62
+
63
+
64
+ v0.5.8
65
+ ------
66
+
67
+ - Swagger json includes apipie's description as swagger's description [\#615](https://github.com/Apipie/apipie-rails/pull/615) ([gogotanaka](https://github.com/gogotanaka))
68
+ - Fix api! issue by using underscore when appending `controller` to the default controller string [\#613](https://github.com/Apipie/apipie-rails/pull/613) ([kevinmarx](https://github.com/kevinmarx))
69
+ - Possibility to compress examples [\#600](https://github.com/Apipie/apipie-rails/pull/600) ([Haniyya](https://github.com/Haniyya))
70
+ - Possibility to describe responses [\#588](https://github.com/Apipie/apipie-rails/pull/588) ([elasti-ron](https://github.com/elasti-ron))
71
+
72
+ v0.5.7
73
+ ------
74
+
75
+ - Fix example recording with Rails 5 [\#607](https://github.com/Apipie/apipie-rails/pull/607) ([adamruzicka](https://github.com/adamruzicka))
76
+ - Use SHA1 instead of MD5 to enable using APIPIE at FIPS-enables systems [\#605](https://github.com/Apipie/apipie-rails/pull/605) ([iNecas](https://github.com/iNecas))
77
+ - Replaced String\#constantize with String\#safe\_constantize so apipie won't break on a missing constant [\#575](https://github.com/Apipie/apipie-rails/pull/575) ([Haniyya](https://github.com/Haniyya))
78
+ - Added Swagger generation [\#569](https://github.com/Apipie/apipie-rails/pull/569) ([elasti-ron](https://github.com/elasti-ron))
79
+
80
+ v0.5.6
81
+ ------
82
+
83
+ - Prevent missing translation span in title [\#571](https://github.com/Apipie/apipie-rails/pull/571) ([mbacovsky](https://github.com/mbacovsky))
84
+ - Clean up old generator code for CLI [\#572](https://github.com/Apipie/apipie-rails/pull/572) ([voxik](https://github.com/voxik))
85
+ - Added french locale [\#568](https://github.com/Apipie/apipie-rails/pull/568) ([giglemad](https://github.com/giglemad))
86
+
87
+ v0.5.5
88
+ ------
89
+
90
+ - prevent lang in url when config.translate is false [\#562](https://github.com/Apipie/apipie-rails/pull/562) ([markmoser](https://github.com/markmoser))
91
+ - Allow for resource-level deprecations [\#567](https://github.com/Apipie/apipie-rails/pull/567) ([cross-p6](https://github.com/cross-p6))
92
+
93
+ v0.5.4
94
+ ------
95
+
96
+ - Constantize controller class before calling superclass [\#558](https://github.com/Apipie/apipie-rails/pull/558) ([ydkn](https://github.com/ydkn))
97
+
98
+ v0.5.3
99
+ ------
100
+
101
+ - Fix reloading when extending the apidoc from concern [\#557](https://github.com/Apipie/apipie-rails/pull/557) ([iNecas](https://github.com/iNecas))
102
+ - Fix example recording when using send\_file [\#504](https://github.com/Apipie/apipie-rails/pull/504) ([tdeo](https://github.com/tdeo))
103
+
104
+ v0.5.2
105
+ ------
106
+
107
+ - A way to extend an exiting API via concern [\#554](https://github.com/Apipie/apipie-rails/pull/554) ([iNecas](https://github.com/iNecas))
108
+ - Fallback to apipie views when application override isn't present [\#552](https://github.com/Apipie/apipie-rails/pull/552) ([tstrachota](https://github.com/tstrachota))
109
+ - Updated setting default locale for api documentation [\#543](https://github.com/Apipie/apipie-rails/pull/543) ([DmitryKK](https://github.com/DmitryKK))
110
+
111
+ v0.5.1
112
+ ------
113
+
114
+ - Use AD::Reloader on Rails 4, app.reloader only on Rails 5+ [\#541](https://github.com/Apipie/apipie-rails/pull/541) ([domcleal](https://github.com/domcleal))
115
+ - Recognize Rack Symbols as Status Codes [\#468](https://github.com/Apipie/apipie-rails/pull/468)([alex-tan](https://github.com/alex-tan))
116
+
117
+ v0.5.0
118
+ ------
119
+
120
+ - Fix Rails 5.1 deprecations [\#530](https://github.com/Apipie/apipie-rails/pull/530) ([@Onumis](https://github.com/Onumis) [@sedx](https://github.com/sedx))
121
+ - **This release is no longer compatible with Ruby 1.9.x**
122
+ - Do not mutate strings passed as config options, fixes \#461 [\#537](https://github.com/Apipie/apipie-rails/pull/537) ([samphilipd](https://github.com/samphilipd))
123
+ - Added recursion for documentation, fixed bug in examples with paperclip [\#531](https://github.com/Apipie/apipie-rails/pull/531) ([blddmnd](https://github.com/blddmnd))
124
+ - Added locales/ja.yml for Japanese [\#529](https://github.com/Apipie/apipie-rails/pull/529) ([kikuchi0808](https://github.com/kikuchi0808))
125
+
126
+
127
+ v0.4.0
128
+ ------
129
+
130
+ - Rails 5 compatibility [\#527](https://github.com/Apipie/apipie-rails/pull/527) ([iNecas](https://github.com/iNecas)) [\#420](https://github.com/Apipie/apipie-rails/pull/420) ([buren](https://github.com/buren)) [\#473](https://github.com/Apipie/apipie-rails/pull/473)([domcleal](https://github.com/domcleal))
131
+ - **This release is no longer compatible with Rails 3.x**
132
+ - Include delete request parmeters in generated documentation [\#524](https://github.com/Apipie/apipie-rails/pull/524) ([johnnaegle](https://github.com/johnnaegle))
133
+ - Allow a blank, not just nil, base\_url. [\#521](https://github.com/Apipie/apipie-rails/pull/521) ([johnnaegle](https://github.com/johnnaegle))
134
+ - Adds allow\_blank option [\#508](https://github.com/Apipie/apipie-rails/pull/508) ([MrLeebo](https://github.com/MrLeebo))
135
+ - Boolean Validator uses \<code\> instead of ' [\#502](https://github.com/Apipie/apipie-rails/pull/502) ([berfarah](https://github.com/berfarah))
136
+ - Fix type validator message [\#501](https://github.com/Apipie/apipie-rails/pull/501) ([cindygu-itglue](https://github.com/cindygu-itglue))
137
+ - Add IT locale [\#496](https://github.com/Apipie/apipie-rails/pull/496) ([alepore](https://github.com/alepore))
138
+ - Fix small typo on dsl\_definition data init [\#494](https://github.com/Apipie/apipie-rails/pull/494) ([begault](https://github.com/begault))
139
+ - Localize app info message [\#491](https://github.com/Apipie/apipie-rails/pull/491) ([belousovAV](https://github.com/belousovAV))
140
+ - Fix travis build [\#489](https://github.com/Apipie/apipie-rails/pull/489) ([mtparet](https://github.com/mtparet))
141
+ - Handle blank data when parsing a example's response [\#453](https://github.com/Apipie/apipie-rails/pull/453) ([stbenjam](https://github.com/stbenjam))
142
+ - Allow layouts to be overridable. Fixes a regression introduced in \#425. [\#447](https://github.com/Apipie/apipie-rails/pull/447) ([nilsojes](https://github.com/nilsojes))
143
+
144
+ v0.3.7
145
+ ------
146
+
147
+ - Handle blank data when parsing a example's response [\#453](https://github.com/Apipie/apipie-rails/pull/453) ([stbenjam](https://github.com/stbenjam))
148
+ - Allow layouts to be overridable. Fixes a regression introduced in \#425. [\#447](https://github.com/Apipie/apipie-rails/pull/447) ([nilseriksson](https://github.com/nilseriksson))
149
+
5
150
  v0.3.6
6
151
  ------
7
152
 
@@ -70,7 +215,7 @@ v0.3.2
70
215
  v0.3.1
71
216
  ------
72
217
 
73
- * Support for ``api!`` keyword in concerns
218
+ * Support for ``api!`` keyword in concerns
74
219
  [#322](https://github.com/Apipie/apipie-rails/pull/322) [@iNecas][]
75
220
  * More explicit ordering of the static dispatcher middleware
76
221
  [#315](https://github.com/Apipie/apipie-rails/pull/315) [@iNecas][]
data/Gemfile ADDED
@@ -0,0 +1 @@
1
+ ./Gemfile.rails50
data/Gemfile.rails41 CHANGED
@@ -3,3 +3,5 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  gem 'rails', '~> 4.1.0'
6
+ gem 'mime-types', '~> 2.99.3'
7
+ gem 'test_engine', path: 'spec/dummy/components/test_engine', group: :test
data/Gemfile.rails42 CHANGED
@@ -2,4 +2,13 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 4.2.5.1'
5
+ gem 'rails', '~> 4.2.5'
6
+ gem 'mime-types', '~> 2.99.3'
7
+ gem 'sqlite3', '~> 1.3.6'
8
+
9
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.1.0')
10
+ gem 'nokogiri', '~> 1.6.8'
11
+ gem 'rdoc', '~> 4.2.2'
12
+ end
13
+
14
+ gem 'test_engine', path: 'spec/dummy/components/test_engine', group: :test
data/Gemfile.rails50 ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'rails', '~> 5.0.0'
6
+ gem 'mime-types', '~> 2.99.3'
7
+ gem 'rails-controller-testing'
8
+
9
+ gem 'test_engine', path: 'spec/dummy/components/test_engine', group: :test
data/Gemfile.rails51 ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'rails', '~> 5.1.0.rc1'
6
+ gem 'mime-types', '~> 2.99.3'
7
+ gem 'rails-controller-testing'
8
+
9
+ gem 'test_engine', path: 'spec/dummy/components/test_engine', group: :test
data/Gemfile.rails60 ADDED
@@ -0,0 +1,14 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'rails', '~> 6.0.0.rc1'
6
+ gem 'mime-types', '~> 2.99.3'
7
+ gem 'rails-controller-testing'
8
+ gem 'rspec-rails', git: 'https://github.com/rspec/rspec-rails', branch: '4-0-dev'
9
+ gem 'rspec-core', git: 'https://github.com/rspec/rspec-core'
10
+ gem 'rspec-mocks', git: 'https://github.com/rspec/rspec-mocks'
11
+ gem 'rspec-support', git: 'https://github.com/rspec/rspec-support'
12
+ gem 'rspec-expectations', git: 'https://github.com/rspec/rspec-expectations'
13
+
14
+ gem 'test_engine', path: 'spec/dummy/components/test_engine', group: :test
@@ -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
+