apipierails3 0.0.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 (171) hide show
  1. checksums.yaml +17 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +27 -0
  5. data/APACHE-LICENSE-2.0 +202 -0
  6. data/CHANGELOG.md +469 -0
  7. data/Gemfile +1 -0
  8. data/Gemfile.rails32 +6 -0
  9. data/Gemfile.rails41 +6 -0
  10. data/Gemfile.rails42 +11 -0
  11. data/Gemfile.rails50 +6 -0
  12. data/Gemfile.rails51 +7 -0
  13. data/MIT-LICENSE +20 -0
  14. data/NOTICE +4 -0
  15. data/PROPOSAL_FOR_RESPONSE_DESCRIPTIONS.md +244 -0
  16. data/README.rst +1874 -0
  17. data/Rakefile +13 -0
  18. data/apipierails3.gemspec +27 -0
  19. data/app/controllers/apipie/apipies_controller.rb +199 -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 +138 -0
  23. data/app/public/apipie/javascripts/bundled/bootstrap.js +1726 -0
  24. data/app/public/apipie/javascripts/bundled/jquery.js +5 -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 +12 -0
  28. data/app/public/apipie/stylesheets/bundled/bootstrap.min.css +689 -0
  29. data/app/public/apipie/stylesheets/bundled/prettify.css +30 -0
  30. data/app/views/apipie/apipies/_disqus.html.erb +13 -0
  31. data/app/views/apipie/apipies/_errors.html.erb +23 -0
  32. data/app/views/apipie/apipies/_headers.html.erb +26 -0
  33. data/app/views/apipie/apipies/_languages.erb +6 -0
  34. data/app/views/apipie/apipies/_metadata.erb +1 -0
  35. data/app/views/apipie/apipies/_method_detail.erb +61 -0
  36. data/app/views/apipie/apipies/_params.html.erb +42 -0
  37. data/app/views/apipie/apipies/_params_plain.html.erb +20 -0
  38. data/app/views/apipie/apipies/apipie_404.html.erb +17 -0
  39. data/app/views/apipie/apipies/apipie_checksum.json.erb +1 -0
  40. data/app/views/apipie/apipies/getting_started.html.erb +6 -0
  41. data/app/views/apipie/apipies/index.html.erb +56 -0
  42. data/app/views/apipie/apipies/method.html.erb +41 -0
  43. data/app/views/apipie/apipies/plain.html.erb +77 -0
  44. data/app/views/apipie/apipies/resource.html.erb +80 -0
  45. data/app/views/apipie/apipies/static.html.erb +103 -0
  46. data/app/views/layouts/apipie/apipie.html.erb +27 -0
  47. data/config/locales/de.yml +28 -0
  48. data/config/locales/en.yml +32 -0
  49. data/config/locales/es.yml +28 -0
  50. data/config/locales/fr.yml +31 -0
  51. data/config/locales/it.yml +31 -0
  52. data/config/locales/ja.yml +31 -0
  53. data/config/locales/pl.yml +28 -0
  54. data/config/locales/pt-BR.yml +28 -0
  55. data/config/locales/ru.yml +28 -0
  56. data/config/locales/tr.yml +28 -0
  57. data/config/locales/zh-CN.yml +28 -0
  58. data/config/locales/zh-TW.yml +28 -0
  59. data/images/screenshot-1.png +0 -0
  60. data/images/screenshot-2.png +0 -0
  61. data/lib/apipie/apipie_module.rb +83 -0
  62. data/lib/apipie/application.rb +462 -0
  63. data/lib/apipie/configuration.rb +186 -0
  64. data/lib/apipie/dsl_definition.rb +607 -0
  65. data/lib/apipie/error_description.rb +44 -0
  66. data/lib/apipie/errors.rb +86 -0
  67. data/lib/apipie/extractor.rb +177 -0
  68. data/lib/apipie/extractor/collector.rb +117 -0
  69. data/lib/apipie/extractor/recorder.rb +166 -0
  70. data/lib/apipie/extractor/writer.rb +454 -0
  71. data/lib/apipie/helpers.rb +73 -0
  72. data/lib/apipie/markup.rb +48 -0
  73. data/lib/apipie/method_description.rb +273 -0
  74. data/lib/apipie/middleware/checksum_in_headers.rb +35 -0
  75. data/lib/apipie/param_description.rb +280 -0
  76. data/lib/apipie/railtie.rb +9 -0
  77. data/lib/apipie/resource_description.rb +124 -0
  78. data/lib/apipie/response_description.rb +131 -0
  79. data/lib/apipie/response_description_adapter.rb +200 -0
  80. data/lib/apipie/routes_formatter.rb +33 -0
  81. data/lib/apipie/routing.rb +16 -0
  82. data/lib/apipie/rspec/response_validation_helper.rb +192 -0
  83. data/lib/apipie/see_description.rb +39 -0
  84. data/lib/apipie/static_dispatcher.rb +69 -0
  85. data/lib/apipie/swagger_generator.rb +707 -0
  86. data/lib/apipie/tag_list_description.rb +11 -0
  87. data/lib/apipie/validator.rb +526 -0
  88. data/lib/apipie/version.rb +3 -0
  89. data/lib/apipierails3.rb +25 -0
  90. data/lib/generators/apipie/install/README +6 -0
  91. data/lib/generators/apipie/install/install_generator.rb +25 -0
  92. data/lib/generators/apipie/install/templates/initializer.rb.erb +7 -0
  93. data/lib/generators/apipie/views_generator.rb +11 -0
  94. data/lib/tasks/apipie.rake +345 -0
  95. data/rel-eng/packages/.readme +3 -0
  96. data/rel-eng/packages/rubygem-apipie-rails +1 -0
  97. data/rel-eng/tito.props +5 -0
  98. data/spec/controllers/api/v1/architectures_controller_spec.rb +29 -0
  99. data/spec/controllers/api/v2/architectures_controller_spec.rb +12 -0
  100. data/spec/controllers/api/v2/nested/resources_controller_spec.rb +11 -0
  101. data/spec/controllers/apipies_controller_spec.rb +273 -0
  102. data/spec/controllers/concerns_controller_spec.rb +42 -0
  103. data/spec/controllers/extended_controller_spec.rb +11 -0
  104. data/spec/controllers/users_controller_spec.rb +740 -0
  105. data/spec/dummy/Rakefile +7 -0
  106. data/spec/dummy/app/controllers/api/base_controller.rb +4 -0
  107. data/spec/dummy/app/controllers/api/v1/architectures_controller.rb +43 -0
  108. data/spec/dummy/app/controllers/api/v1/base_controller.rb +11 -0
  109. data/spec/dummy/app/controllers/api/v2/architectures_controller.rb +30 -0
  110. data/spec/dummy/app/controllers/api/v2/base_controller.rb +11 -0
  111. data/spec/dummy/app/controllers/api/v2/nested/architectures_controller.rb +32 -0
  112. data/spec/dummy/app/controllers/api/v2/nested/resources_controller.rb +33 -0
  113. data/spec/dummy/app/controllers/application_controller.rb +18 -0
  114. data/spec/dummy/app/controllers/concerns/extending_concern.rb +11 -0
  115. data/spec/dummy/app/controllers/concerns/sample_controller.rb +41 -0
  116. data/spec/dummy/app/controllers/concerns_controller.rb +8 -0
  117. data/spec/dummy/app/controllers/extended_controller.rb +14 -0
  118. data/spec/dummy/app/controllers/files_controller.rb +5 -0
  119. data/spec/dummy/app/controllers/overridden_concerns_controller.rb +31 -0
  120. data/spec/dummy/app/controllers/pets_controller.rb +408 -0
  121. data/spec/dummy/app/controllers/pets_using_auto_views_controller.rb +73 -0
  122. data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +95 -0
  123. data/spec/dummy/app/controllers/tagged_cats_controller.rb +32 -0
  124. data/spec/dummy/app/controllers/tagged_dogs_controller.rb +15 -0
  125. data/spec/dummy/app/controllers/twitter_example_controller.rb +307 -0
  126. data/spec/dummy/app/controllers/users_controller.rb +297 -0
  127. data/spec/dummy/app/views/layouts/application.html.erb +21 -0
  128. data/spec/dummy/config.ru +4 -0
  129. data/spec/dummy/config/application.rb +49 -0
  130. data/spec/dummy/config/boot.rb +10 -0
  131. data/spec/dummy/config/database.yml +21 -0
  132. data/spec/dummy/config/environment.rb +8 -0
  133. data/spec/dummy/config/environments/development.rb +28 -0
  134. data/spec/dummy/config/environments/production.rb +52 -0
  135. data/spec/dummy/config/environments/test.rb +38 -0
  136. data/spec/dummy/config/initializers/apipie.rb +110 -0
  137. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  138. data/spec/dummy/config/initializers/inflections.rb +10 -0
  139. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  140. data/spec/dummy/config/initializers/secret_token.rb +8 -0
  141. data/spec/dummy/config/initializers/session_store.rb +8 -0
  142. data/spec/dummy/config/locales/en.yml +5 -0
  143. data/spec/dummy/config/routes.rb +51 -0
  144. data/spec/dummy/db/.gitkeep +0 -0
  145. data/spec/dummy/doc/apipie_examples.json +1 -0
  146. data/spec/dummy/doc/users/desc_from_file.md +1 -0
  147. data/spec/dummy/public/404.html +26 -0
  148. data/spec/dummy/public/422.html +26 -0
  149. data/spec/dummy/public/500.html +26 -0
  150. data/spec/dummy/public/favicon.ico +0 -0
  151. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  152. data/spec/dummy/script/rails +6 -0
  153. data/spec/lib/application_spec.rb +49 -0
  154. data/spec/lib/extractor/extractor_spec.rb +9 -0
  155. data/spec/lib/extractor/middleware_spec.rb +44 -0
  156. data/spec/lib/extractor/writer_spec.rb +110 -0
  157. data/spec/lib/file_handler_spec.rb +18 -0
  158. data/spec/lib/method_description_spec.rb +98 -0
  159. data/spec/lib/param_description_spec.rb +345 -0
  160. data/spec/lib/param_group_spec.rb +60 -0
  161. data/spec/lib/rake_spec.rb +71 -0
  162. data/spec/lib/resource_description_spec.rb +48 -0
  163. data/spec/lib/swagger/openapi_2_0_schema.json +1607 -0
  164. data/spec/lib/swagger/rake_swagger_spec.rb +139 -0
  165. data/spec/lib/swagger/response_validation_spec.rb +104 -0
  166. data/spec/lib/swagger/swagger_dsl_spec.rb +658 -0
  167. data/spec/lib/validator_spec.rb +113 -0
  168. data/spec/lib/validators/array_validator_spec.rb +85 -0
  169. data/spec/spec_helper.rb +109 -0
  170. data/spec/support/rake.rb +21 -0
  171. metadata +415 -0
@@ -0,0 +1,33 @@
1
+ module Apipie
2
+ class RoutesFormatter
3
+ API_METHODS = %w{GET POST PUT PATCH OPTIONS DELETE}
4
+
5
+ # The entry method called by Apipie to extract the array
6
+ # representing the api dsl from the routes definition.
7
+ def format_routes(rails_routes, args)
8
+ rails_routes.map { |rails_route| format_route(rails_route, args) }
9
+ end
10
+
11
+ def format_route(rails_route, args)
12
+ { :path => format_path(rails_route),
13
+ :verb => format_verb(rails_route),
14
+ :desc => args[:desc],
15
+ :options => args[:options] }
16
+ end
17
+
18
+ def format_path(rails_route)
19
+ rails_route.path.spec.to_s.gsub('(.:format)', '')
20
+ end
21
+
22
+ def format_verb(rails_route)
23
+ verb = API_METHODS.select{|defined_verb| defined_verb =~ /\A#{rails_route.verb}\z/}
24
+ if verb.count != 1
25
+ verb = API_METHODS.select{|defined_verb| defined_verb == rails_route.constraints[:method]}
26
+ if verb.blank?
27
+ raise "Unknow verb #{rails_route.path.spec.to_s}"
28
+ end
29
+ end
30
+ verb.first
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,16 @@
1
+ module Apipie
2
+ module Routing
3
+ module MapperExtensions
4
+ def apipie(options = {})
5
+ namespace "apipie", :path => Apipie.configuration.doc_base_url do
6
+ get 'apipie_checksum', :to => "apipies#apipie_checksum", :format => "json"
7
+ constraints(:version => /[^\/]+/, :resource => /[^\/]+/, :method => /[^\/]+/) do
8
+ get(options.reverse_merge("(:version)/(:resource)/(:method)" => "apipies#index", :as => :apipie))
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ ActionDispatch::Routing::Mapper.send :include, Apipie::Routing::MapperExtensions
@@ -0,0 +1,192 @@
1
+ #----------------------------------------------------------------------------------------------
2
+ # response_validation_helper.rb:
3
+ #
4
+ # this is an rspec utility to allow validation of responses against the swagger schema generated
5
+ # from the Apipie 'returns' definition for the call.
6
+ #
7
+ #
8
+ # to use this file in a controller rspec you should
9
+ # require 'apipie/rspec/response_validation_helper' in the spec file
10
+ #
11
+ #
12
+ # this utility provides two mechanisms: matcher-based validation and auto-validation
13
+ #
14
+ # matcher-based: an rspec matcher allowing 'expect(response).to match_declared_responses'
15
+ # auto-validation: all responses returned from 'get', 'post', etc. are automatically tested
16
+ #
17
+ # ===================================
18
+ # Matcher-based validation - example
19
+ # ===================================
20
+ # Assume the file 'my_controller_spec.rb':
21
+ #
22
+ # require 'apipie/rspec/response_validation_helper'
23
+ #
24
+ # RSpec.describe MyController, :type => :controller, :show_in_doc => true do
25
+ #
26
+ # describe "GET stuff with response validation" do
27
+ # render_views # this makes sure the 'get' operation will actually
28
+ # # return the rendered view even though this is a Controller spec
29
+ #
30
+ # it "does something" do
31
+ # response = get :index, {format: :json}
32
+ #
33
+ # # the following expectation will fail if the returned object
34
+ # # does not match the 'returns' declaration in the Controller,
35
+ # # or if there is no 'returns' declaration for the returned
36
+ # # HTTP status code
37
+ # expect(response).to match_declared_responses
38
+ # end
39
+ # end
40
+ #
41
+ #
42
+ # ===================================
43
+ # Auto-validation
44
+ # ===================================
45
+ # To use auto-validation, at the beginning of the block in which you want to turn on validation:
46
+ # -) turn on view rendering (by stating 'render_views')
47
+ # -) turn on response validation by stating 'auto_validate_rendered_views'
48
+ #
49
+ # For example, assume the file 'my_controller_spec.rb':
50
+ #
51
+ # require 'apipie/rspec/response_validation_helper'
52
+ #
53
+ # RSpec.describe MyController, :type => :controller, :show_in_doc => true do
54
+ #
55
+ # describe "GET stuff with response validation" do
56
+ # render_views
57
+ # auto_validate_rendered_views
58
+ #
59
+ # it "does something" do
60
+ # get :index, {format: :json}
61
+ # end
62
+ # it "does something else" do
63
+ # get :another_index, {format: :json}
64
+ # end
65
+ # end
66
+ #
67
+ # describe "GET stuff without response validation" do
68
+ # it "does something" do
69
+ # get :index, {format: :json}
70
+ # end
71
+ # it "does something else" do
72
+ # get :another_index, {format: :json}
73
+ # end
74
+ # end
75
+ #
76
+ #
77
+ # Once this is done, responses from http operations ('get', 'post', 'delete', etc.)
78
+ # will fail the test if the response structure does not match the 'returns' declaration
79
+ # on the method (for the actual HTTP status code), or if there is no 'returns' declaration
80
+ # for the HTTP status code.
81
+ #----------------------------------------------------------------------------------------------
82
+
83
+
84
+ #----------------------------------------------------------------------------------------------
85
+ # Response validation: core logic (used by auto-validation and manual-validation mechanisms)
86
+ #----------------------------------------------------------------------------------------------
87
+ class ActionController::Base
88
+ module Apipie::ControllerValidationHelpers
89
+ # this method is injected into ActionController::Base in order to
90
+ # get access to the names of the current controller, current action, as well as to the response
91
+ def schema_validation_errors_for_response
92
+ unprocessed_schema = Apipie::json_schema_for_method_response(controller_name, action_name, response.code, true)
93
+
94
+ if unprocessed_schema.nil?
95
+ err = "no schema defined for #{controller_name}##{action_name}[#{response.code}]"
96
+ return [nil, [err], RuntimeError.new(err)]
97
+ end
98
+
99
+ schema = JSON.parse(JSON(unprocessed_schema))
100
+
101
+ error_list = JSON::Validator.fully_validate(schema, response.body, :strict => false, :version => :draft4, :json => true)
102
+
103
+ error_object = Apipie::ResponseDoesNotMatchSwaggerSchema.new(controller_name, action_name, response.code, error_list, schema, response.body)
104
+
105
+ [schema, error_list, error_object]
106
+ rescue Apipie::NoDocumentedMethod
107
+ [nil, [], nil]
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ module Apipie
114
+ def self.print_validation_errors(validation_errors, schema, response, error_object=nil)
115
+ Rails.logger.warn(validation_errors.to_s)
116
+ if Rails.env.test?
117
+ puts "schema validation errors:"
118
+ validation_errors.each { |e| puts "--> #{e.to_s}" }
119
+ puts "schema: #{schema.nil? ? '<none>' : JSON(schema)}"
120
+ puts "response: #{response.body}"
121
+ raise error_object if error_object
122
+ end
123
+ end
124
+ end
125
+
126
+ #---------------------------------
127
+ # Manual-validation (RSpec matcher)
128
+ #---------------------------------
129
+ RSpec::Matchers.define :match_declared_responses do
130
+ match do |actual|
131
+ (schema, validation_errors) = subject.send(:schema_validation_errors_for_response)
132
+ valid = (validation_errors == [])
133
+ Apipie::print_validation_errors(validation_errors, schema, response) unless valid
134
+
135
+ valid
136
+ end
137
+ end
138
+
139
+
140
+ #---------------------------------
141
+ # Auto-validation logic
142
+ #---------------------------------
143
+ module RSpec::Rails::ViewRendering
144
+ # Augment the RSpec DSL
145
+ module ClassMethods
146
+ def auto_validate_rendered_views
147
+ before do
148
+ @is_response_validation_on = true
149
+ end
150
+
151
+ after do
152
+ @is_response_validation_on = false
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+
159
+ ActionController::TestCase::Behavior.instance_eval do
160
+ # instrument the 'process' method in ActionController::TestCase to enable response validation
161
+ module Apipie::ResponseValidationHelpers
162
+ @is_response_validation_on = false
163
+ def process(*args)
164
+ result = super(*args)
165
+ validate_response if @is_response_validation_on
166
+
167
+ result
168
+ end
169
+
170
+ def validate_response
171
+ controller.send(:validate_response_and_abort_with_info_if_errors)
172
+ end
173
+ end
174
+
175
+ end
176
+
177
+
178
+ class ActionController::Base
179
+ module Apipie::ControllerValidationHelpers
180
+ def validate_response_and_abort_with_info_if_errors
181
+
182
+ (schema, validation_errors, error_object) = schema_validation_errors_for_response
183
+
184
+ valid = (validation_errors == [])
185
+ if !valid
186
+ Apipie::print_validation_errors(validation_errors, schema, response, error_object)
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+
@@ -0,0 +1,39 @@
1
+ module Apipie
2
+
3
+ class SeeDescription
4
+
5
+ attr_reader :link, :description
6
+
7
+ def initialize(args)
8
+ if args.first.is_a? Hash
9
+ args = args.first
10
+ elsif args.count == 2
11
+ if args.last.is_a? Hash
12
+ args = {:link => args.first}.merge(args.last)
13
+ else
14
+ args = {:link => args.first, :description => args.second}
15
+ end
16
+ elsif args.count == 1 && args.first.is_a?(String)
17
+ args = {:link => args.first, :description => args.first}
18
+ else
19
+ raise ArgumentError "ApipieError: Bad use of see method."
20
+ end
21
+ @link = args[:link] || args['link']
22
+ @description = args[:desc] || args[:description] || args['desc'] || args['description']
23
+ end
24
+
25
+ def to_json
26
+ {:link => see_url, :description => description}
27
+ end
28
+
29
+ def see_url
30
+ method_description = Apipie[@link]
31
+ if method_description.nil?
32
+ raise ArgumentError.new("Method #{@link} referenced in 'see' does not exist.")
33
+ end
34
+ method_description.doc_url
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,69 @@
1
+ module Apipie
2
+
3
+ class FileHandler
4
+ def initialize(root)
5
+ @root = root.chomp('/')
6
+ @compiled_root = /^#{Regexp.escape(root)}/
7
+ @file_server = ::Rack::File.new(@root)
8
+ end
9
+
10
+ def match?(path)
11
+ # Replace all null bytes
12
+ path = ::Rack::Utils.unescape(path || '').gsub(/\x0/, '')
13
+
14
+ full_path = path.empty? ? @root : File.join(@root, path)
15
+ paths = "#{full_path}#{ext}"
16
+
17
+ matches = Dir[paths]
18
+ match = matches.detect { |m| File.file?(m) }
19
+ if match
20
+ match.sub!(@compiled_root, '')
21
+ match
22
+ end
23
+ end
24
+
25
+ def call(env)
26
+ @file_server.call(env)
27
+ end
28
+
29
+ def ext
30
+ @ext ||= begin
31
+ ext = cache_extension
32
+ "{,#{ext},/index#{ext}}"
33
+ end
34
+ end
35
+
36
+ def cache_extension
37
+ if ::ActionController::Base.respond_to?(:default_static_extension)
38
+ ::ActionController::Base.default_static_extension
39
+ else
40
+ ::ActionController::Base.page_cache_extension
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+ class StaticDispatcher
47
+ # Dispatches the static files. Similar to ActionDispatch::Static, but
48
+ # it supports different baseurl configurations
49
+ def initialize(app, path)
50
+ @app = app
51
+ @file_handler = Apipie::FileHandler.new(path)
52
+ end
53
+
54
+ def call(env)
55
+ @baseurl ||= Apipie.configuration.doc_base_url
56
+ case env['REQUEST_METHOD']
57
+ when 'GET', 'HEAD'
58
+ path = env['PATH_INFO'].sub("#{@baseurl}/","/apipie/").chomp('/')
59
+
60
+ if match = @file_handler.match?(path)
61
+ env["PATH_INFO"] = match
62
+ return @file_handler.call(env)
63
+ end
64
+ end
65
+
66
+ @app.call(env)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,707 @@
1
+ module Apipie
2
+
3
+ #--------------------------------------------------------------------------
4
+ # Configuration. Should be moved to Apipie config.
5
+ #--------------------------------------------------------------------------
6
+ class SwaggerGenerator
7
+ require 'json'
8
+ require 'ostruct'
9
+ require 'open3'
10
+ require 'zlib' if Apipie.configuration.swagger_generate_x_computed_id_field?
11
+
12
+ attr_reader :computed_interface_id
13
+
14
+ def initialize(apipie)
15
+ @apipie = apipie
16
+ @issued_warnings = []
17
+ end
18
+
19
+ def params_in_body?
20
+ Apipie.configuration.swagger_content_type_input == :json
21
+ end
22
+
23
+ def params_in_body_use_reference?
24
+ Apipie.configuration.swagger_json_input_uses_refs
25
+ end
26
+
27
+ def responses_use_reference?
28
+ Apipie.configuration.swagger_responses_use_refs?
29
+ end
30
+
31
+ def include_warning_tags?
32
+ Apipie.configuration.swagger_include_warning_tags
33
+ end
34
+
35
+
36
+ def generate_from_resources(version, resources, method_name, lang, clear_warnings=false)
37
+ init_swagger_vars(version, lang, clear_warnings)
38
+
39
+ @lang = lang
40
+ @only_method = method_name
41
+ add_resources(resources)
42
+
43
+ @swagger[:info]["x-computed-id"] = @computed_interface_id if Apipie.configuration.swagger_generate_x_computed_id_field?
44
+ return @swagger
45
+ end
46
+
47
+
48
+ #--------------------------------------------------------------------------
49
+ # Initialization
50
+ #--------------------------------------------------------------------------
51
+
52
+ def init_swagger_vars(version, lang, clear_warnings=false)
53
+
54
+ # docs = {
55
+ # :name => Apipie.configuration.app_name,
56
+ # :info => Apipie.app_info(version, lang),
57
+ # :copyright => Apipie.configuration.copyright,
58
+ # :doc_url => Apipie.full_url(url_args),
59
+ # :api_url => Apipie.api_base_url(version),
60
+ # :resources => _resources
61
+ # }
62
+
63
+
64
+ @swagger = {
65
+ swagger: '2.0',
66
+ info: {
67
+ title: "#{Apipie.configuration.app_name}",
68
+ description: "#{Apipie.app_info(version, lang)}#{Apipie.configuration.copyright}",
69
+ version: "#{version}",
70
+ "x-copyright" => Apipie.configuration.copyright,
71
+ },
72
+ basePath: Apipie.api_base_url(version),
73
+ consumes: [],
74
+ paths: {},
75
+ definitions: {},
76
+ tags: [],
77
+ }
78
+
79
+ if Apipie.configuration.swagger_api_host
80
+ @swagger[:host] = Apipie.configuration.swagger_api_host
81
+ end
82
+
83
+ if params_in_body?
84
+ @swagger[:consumes] = ['application/json']
85
+ @swagger[:info][:title] += " (params in:body)"
86
+ else
87
+ @swagger[:consumes] = ['application/x-www-form-urlencoded', 'multipart/form-data']
88
+ @swagger[:info][:title] += " (params in:formData)"
89
+ end
90
+
91
+ @paths = @swagger[:paths]
92
+ @definitions = @swagger[:definitions]
93
+ @tags = @swagger[:tags]
94
+
95
+ @issued_warnings = [] if clear_warnings || @issued_warnings.nil?
96
+ @computed_interface_id = 0
97
+
98
+ @current_lang = lang
99
+ end
100
+
101
+ #--------------------------------------------------------------------------
102
+ # Engine interface methods
103
+ #--------------------------------------------------------------------------
104
+
105
+ def add_resources(resources)
106
+ resources.each do |resource_name, resource_defs|
107
+ add_resource_description(resource_name, resource_defs)
108
+ add_resource_methods(resource_name, resource_defs)
109
+ end
110
+ end
111
+
112
+ def add_resource_methods(resource_name, resource_defs)
113
+ resource_defs._methods.each do |apipie_method_name, apipie_method_defs|
114
+ add_ruby_method(@paths, apipie_method_defs)
115
+ end
116
+ end
117
+
118
+
119
+ #--------------------------------------------------------------------------
120
+ # Logging, debugging and regression-testing utilities
121
+ #--------------------------------------------------------------------------
122
+
123
+ def ruby_name_for_method(method)
124
+ return "<no method>" if method.nil?
125
+ method.resource.controller.name + "#" + method.method
126
+ end
127
+
128
+
129
+ def warn_missing_method_summary() warn 100, "missing short description for method"; end
130
+ def warn_added_missing_slash(path) warn 101,"added missing / at beginning of path: #{path}"; end
131
+ def warn_no_return_codes_specified() warn 102,"no return codes ('errors') specified"; end
132
+ def warn_hash_without_internal_typespec(param_name) warn 103,"the parameter :#{param_name} is a generic Hash without an internal type specification"; end
133
+ def warn_optional_param_in_path(param_name) warn 104, "the parameter :#{param_name} is 'in-path'. Ignoring 'not required' in DSL"; end
134
+ def warn_optional_without_default_value(param_name) warn 105,"the parameter :#{param_name} is optional but default value is not specified (use :default_value => ...)"; end
135
+ def warn_param_ignored_in_form_data(param_name) warn 106,"ignoring param :#{param_name} -- cannot include Hash without fields in a formData specification"; end
136
+ def warn_path_parameter_not_described(name,path) warn 107,"the parameter :#{name} appears in the path #{path} but is not described"; end
137
+ def warn_inferring_boolean(name) warn 108,"the parameter [#{name}] is Enum with [true,false] values. Inferring 'boolean'"; end
138
+
139
+ def warn(warning_num, msg)
140
+ suppress = Apipie.configuration.swagger_suppress_warnings
141
+ return if suppress == true
142
+ return if suppress.is_a?(Array) && suppress.include?(warning_num)
143
+
144
+ method_id = ruby_name_for_method(@current_method)
145
+ warning_id = "#{method_id}#{warning_num}#{msg}"
146
+
147
+ if @issued_warnings.include?(warning_id)
148
+ # Already issued this warning for the current method
149
+ return
150
+ end
151
+
152
+ print "WARNING (#{warning_num}): [#{method_id}] -- #{msg}\n"
153
+ @issued_warnings.push(warning_id)
154
+ @warnings_issued = true
155
+ end
156
+
157
+ def info(msg)
158
+ print "--- INFO: [#{ruby_name_for_method(@current_method)}] -- #{msg}\n"
159
+ end
160
+
161
+
162
+ # the @computed_interface_id is a number that is uniquely derived from the list of operations
163
+ # added to the swagger definition (in an order-dependent way).
164
+ # it can be used for regression testing, allowing some differentiation between changes that
165
+ # result from changes to the input and those that result from changes to the generation
166
+ # algorithms.
167
+ # note that at the moment, this only takes operation ids into account, and ignores parameter
168
+ # definitions, so it's only partially useful.
169
+ def include_op_id_in_computed_interface_id(op_id)
170
+ @computed_interface_id = Zlib::crc32("#{@computed_interface_id} #{op_id}") if Apipie.configuration.swagger_generate_x_computed_id_field?
171
+ end
172
+
173
+ #--------------------------------------------------------------------------
174
+ # Create a tag description for a described resource
175
+ #--------------------------------------------------------------------------
176
+
177
+ def tag_name_for_resource(resource)
178
+ # resource.controller
179
+ resource._id
180
+ end
181
+
182
+ def add_resource_description(resource_name, resource)
183
+ if resource._full_description
184
+ @tags << {
185
+ name: tag_name_for_resource(resource),
186
+ description: Apipie.app.translate(resource._full_description, @current_lang)
187
+ }
188
+ end
189
+ end
190
+
191
+ #--------------------------------------------------------------------------
192
+ # Create swagger definitions for a ruby method
193
+ #--------------------------------------------------------------------------
194
+
195
+ def add_ruby_method(paths, ruby_method)
196
+
197
+ if @only_method
198
+ return unless ruby_method.method == @only_method
199
+ else
200
+ return if !ruby_method.show
201
+ end
202
+
203
+ for api in ruby_method.apis do
204
+ # controller: ruby_method.resource.controller.name,
205
+
206
+ path = swagger_path(api.path)
207
+ paths[path] ||= {}
208
+ methods = paths[path]
209
+ @current_method = ruby_method
210
+
211
+ @warnings_issued = false
212
+ responses = swagger_responses_hash_for_method(ruby_method)
213
+ if include_warning_tags?
214
+ warning_tags = @warnings_issued ? ['warnings issued'] : []
215
+ else
216
+ warning_tags = []
217
+ end
218
+
219
+ op_id = swagger_op_id_for_path(api.http_method, api.path)
220
+
221
+ include_op_id_in_computed_interface_id(op_id)
222
+
223
+ method_key = api.http_method.downcase
224
+ @current_http_method = method_key
225
+
226
+ methods[method_key] = {
227
+ tags: [tag_name_for_resource(ruby_method.resource)] + warning_tags + ruby_method.tag_list.tags,
228
+ consumes: params_in_body? ? ['application/json'] : ['application/x-www-form-urlencoded', 'multipart/form-data'],
229
+ operationId: op_id,
230
+ summary: Apipie.app.translate(api.short_description, @current_lang),
231
+ parameters: swagger_params_array_for_method(ruby_method, api.path),
232
+ responses: responses,
233
+ description: ruby_method.full_description
234
+ }
235
+
236
+ if methods[method_key][:summary].nil?
237
+ methods[method_key].delete(:summary)
238
+ warn_missing_method_summary
239
+ end
240
+ end
241
+ end
242
+
243
+ #--------------------------------------------------------------------------
244
+ # Utilities for conversion of ruby syntax to swagger syntax
245
+ #--------------------------------------------------------------------------
246
+
247
+ def swagger_path(str)
248
+ str = str.gsub(/:(\w+)/, '{\1}')
249
+ str = str.gsub(/\/$/, '')
250
+
251
+ if str[0] != '/'
252
+ warn_added_missing_slash(str)
253
+ str = '/' + str
254
+ end
255
+ str
256
+ end
257
+
258
+ def remove_colons(str)
259
+ str.gsub(":", "_")
260
+ end
261
+
262
+ def swagger_op_id_for_method(method)
263
+ remove_colons method.resource.controller.name + "::" + method.method
264
+ end
265
+
266
+ def swagger_id_for_typename(typename)
267
+ typename
268
+ end
269
+
270
+ def swagger_op_id_for_path(http_method, path)
271
+ # using lowercase http method, because the 'swagger-codegen' tool outputs
272
+ # strange method names if the http method is in uppercase
273
+ http_method.downcase + path.gsub(/\//,'_').gsub(/:(\w+)/, '\1').gsub(/_$/,'')
274
+ end
275
+
276
+ class SwaggerTypeWithFormat
277
+ attr_reader :str_format
278
+ def initialize(type, str_format)
279
+ @type = type
280
+ @str_format = str_format
281
+ end
282
+
283
+ def to_s
284
+ @type
285
+ end
286
+
287
+ def ==(other)
288
+ other.to_s == self.to_s
289
+ end
290
+ end
291
+
292
+ def lookup
293
+ @lookup ||= {
294
+ numeric: "number",
295
+ hash: "object",
296
+ array: "array",
297
+
298
+ # see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types
299
+ integer: SwaggerTypeWithFormat.new("integer", "int32"),
300
+ long: SwaggerTypeWithFormat.new("integer", "int64"),
301
+ number: SwaggerTypeWithFormat.new("number", nil), # here just for completeness
302
+ float: SwaggerTypeWithFormat.new("number", "float"),
303
+ double: SwaggerTypeWithFormat.new("number", "double"),
304
+ string: SwaggerTypeWithFormat.new("string", nil), # here just for completeness
305
+ byte: SwaggerTypeWithFormat.new("string", "byte"),
306
+ binary: SwaggerTypeWithFormat.new("string", "binary"),
307
+ boolean: SwaggerTypeWithFormat.new("boolean", nil), # here just for completeness
308
+ date: SwaggerTypeWithFormat.new("string", "date"),
309
+ dateTime: SwaggerTypeWithFormat.new("string", "date-time"),
310
+ password: SwaggerTypeWithFormat.new("string", "password"),
311
+ }
312
+ end
313
+
314
+
315
+ def swagger_param_type(param_desc)
316
+ if param_desc.nil?
317
+ raise("problem")
318
+ end
319
+
320
+ v = param_desc.validator
321
+ if v.nil?
322
+ return "string"
323
+ end
324
+
325
+ if v.class == Apipie::Validator::EnumValidator || (v.respond_to?(:is_enum?) && v.is_enum?)
326
+ if v.values - [true, false] == [] && [true, false] - v.values == []
327
+ warn_inferring_boolean(param_desc.name)
328
+ return "boolean"
329
+ else
330
+ return "enum"
331
+ end
332
+ elsif v.class == Apipie::Validator::HashValidator
333
+ # pp v
334
+ end
335
+
336
+
337
+ return lookup[v.expected_type.to_sym] || v.expected_type
338
+ end
339
+
340
+
341
+ #--------------------------------------------------------------------------
342
+ # Responses
343
+ #--------------------------------------------------------------------------
344
+
345
+ def json_schema_for_method_response(method, return_code, allow_nulls)
346
+ @definitions = {}
347
+ for response in method.returns
348
+ if response.code.to_s == return_code.to_s
349
+ schema = response_schema(response, allow_nulls) if response.code.to_s == return_code.to_s
350
+ schema[:definitions] = @definitions if @definitions != {}
351
+ return schema
352
+ end
353
+ end
354
+ nil
355
+ end
356
+
357
+ def json_schema_for_self_describing_class(cls, allow_nulls)
358
+ adapter = ResponseDescriptionAdapter.from_self_describing_class(cls)
359
+ response_schema(adapter, allow_nulls)
360
+ end
361
+
362
+ def response_schema(response, allow_nulls=false)
363
+ begin
364
+ # no need to warn about "missing default value for optional param" when processing response definitions
365
+ prev_value = @disable_default_value_warning
366
+ @disable_default_value_warning = true
367
+
368
+ if responses_use_reference? && response.typename
369
+ schema = {"$ref" => gen_referenced_block_from_params_array(swagger_id_for_typename(response.typename), response.params_ordered, allow_nulls)}
370
+ else
371
+ schema = json_schema_obj_from_params_array(response.params_ordered, allow_nulls)
372
+ end
373
+
374
+ ensure
375
+ @disable_default_value_warning = prev_value
376
+ end
377
+
378
+ if response.is_array? && schema
379
+ schema = {
380
+ type: allow_nulls ? ["array","null"] : "array",
381
+ items: schema
382
+ }
383
+ end
384
+
385
+ if response.allow_additional_properties
386
+ schema[:additionalProperties] = true
387
+ end
388
+
389
+ schema
390
+ end
391
+
392
+ def swagger_responses_hash_for_method(method)
393
+ result = {}
394
+
395
+ for error in method.errors
396
+ error_block = {description: Apipie.app.translate(error.description, @current_lang)}
397
+ result[error.code] = error_block
398
+ end
399
+
400
+ for response in method.returns
401
+ swagger_response_block = {
402
+ description: response.description
403
+ }
404
+
405
+ schema = response_schema(response)
406
+ swagger_response_block[:schema] = schema if schema
407
+
408
+ result[response.code] = swagger_response_block
409
+ end
410
+
411
+ if result.length == 0
412
+ warn_no_return_codes_specified
413
+ result[200] = {description: 'ok'}
414
+ end
415
+
416
+ result
417
+ end
418
+
419
+
420
+
421
+ #--------------------------------------------------------------------------
422
+ # Auto-insertion of parameters that are implicitly defined in the path
423
+ #--------------------------------------------------------------------------
424
+
425
+ def param_names_from_path(path)
426
+ path.scan(/:(\w+)/).map do |ar|
427
+ ar[0].to_sym
428
+ end
429
+ end
430
+
431
+ def add_missing_params(method, path)
432
+ param_names_from_method = method.params.map {|name, desc| name}
433
+ missing = param_names_from_path(path) - param_names_from_method
434
+
435
+ result = method.params
436
+
437
+ missing.each do |name|
438
+ warn_path_parameter_not_described(name, path)
439
+ result[name.to_sym] = OpenStruct.new({
440
+ required: true,
441
+ _gen_added_from_path: true,
442
+ name: name,
443
+ validator: Apipie::Validator::NumberValidator.new(nil),
444
+ options: {
445
+ in: "path"
446
+ }
447
+ })
448
+ end
449
+
450
+ result
451
+ end
452
+
453
+ #--------------------------------------------------------------------------
454
+ # The core routine for creating a swagger parameter definition block.
455
+ # The output is slightly different when the parameter is inside a schema block.
456
+ #--------------------------------------------------------------------------
457
+ def swagger_atomic_param(param_desc, in_schema, name, allow_nulls)
458
+ def save_field(entry, openapi_key, v, apipie_key=openapi_key, translate=false)
459
+ if v.key?(apipie_key)
460
+ if translate
461
+ entry[openapi_key] = Apipie.app.translate(v[apipie_key], @current_lang)
462
+ else
463
+ entry[openapi_key] = v[apipie_key]
464
+ end
465
+ end
466
+ end
467
+
468
+ swagger_def = {}
469
+ swagger_def[:name] = name if !name.nil?
470
+
471
+ swg_param_type = swagger_param_type(param_desc)
472
+ swagger_def[:type] = swg_param_type.to_s
473
+ if (swg_param_type.is_a? SwaggerTypeWithFormat) && !swg_param_type.str_format.nil?
474
+ swagger_def[:format] = swg_param_type.str_format
475
+ end
476
+
477
+ if swagger_def[:type] == "array"
478
+ swagger_def[:items] = {type: "string"}
479
+ end
480
+
481
+ if swagger_def[:type] == "enum"
482
+ swagger_def[:type] = "string"
483
+ swagger_def[:enum] = param_desc.validator.values
484
+ end
485
+
486
+ if swagger_def[:type] == "object" # we only get here if there is no specification of properties for this object
487
+ swagger_def[:additionalProperties] = true
488
+ warn_hash_without_internal_typespec(param_desc.name)
489
+ end
490
+
491
+ if param_desc.is_array?
492
+ new_swagger_def = {
493
+ items: swagger_def,
494
+ type: 'array'
495
+ }
496
+ swagger_def = new_swagger_def
497
+ if allow_nulls
498
+ swagger_def[:type] = [swagger_def[:type], "null"]
499
+ end
500
+ end
501
+
502
+ if allow_nulls
503
+ swagger_def[:type] = [swagger_def[:type], "null"]
504
+ end
505
+
506
+ if !in_schema
507
+ swagger_def[:in] = param_desc.options.fetch(:in, @default_value_for_param_in)
508
+ swagger_def[:required] = param_desc.required if param_desc.required
509
+ end
510
+
511
+ save_field(swagger_def, :description, param_desc.options, :desc, true) unless param_desc.options[:desc].nil?
512
+ save_field(swagger_def, :default, param_desc.options, :default_value)
513
+
514
+ if param_desc.respond_to?(:_gen_added_from_path) && !param_desc.required
515
+ warn_optional_param_in_path(param_desc.name)
516
+ swagger_def[:required] = true
517
+ end
518
+
519
+ if !swagger_def[:required] && !swagger_def.key?(:default)
520
+ warn_optional_without_default_value(param_desc.name) unless @disable_default_value_warning
521
+ end
522
+
523
+ swagger_def
524
+ end
525
+
526
+
527
+ #--------------------------------------------------------------------------
528
+ # JSON schema and referenced-object generation
529
+ #--------------------------------------------------------------------------
530
+
531
+ def ref_to(name)
532
+ "#/definitions/#{name}"
533
+ end
534
+
535
+
536
+ def json_schema_obj_from_params_array(params_array, allow_nulls = false)
537
+ (param_defs, required_params) = json_schema_param_defs_from_params_array(params_array, allow_nulls)
538
+
539
+ result = {type: "object"}
540
+ result[:properties] = param_defs
541
+ result[:additionalProperties] = false unless Apipie.configuration.swagger_allow_additional_properties_in_response
542
+ result[:required] = required_params if required_params.length > 0
543
+
544
+ param_defs.length > 0 ? result : nil
545
+ end
546
+
547
+ def gen_referenced_block_from_params_array(name, params_array, allow_nulls=false)
548
+ return ref_to(:name) if @definitions.key(:name)
549
+
550
+ schema_obj = json_schema_obj_from_params_array(params_array, allow_nulls)
551
+ return nil if schema_obj.nil?
552
+
553
+ @definitions[name.to_sym] = schema_obj
554
+ ref_to(name.to_sym)
555
+ end
556
+
557
+ def json_schema_param_defs_from_params_array(params_array, allow_nulls = false)
558
+ param_defs = {}
559
+ required_params = []
560
+
561
+ params_array ||= []
562
+
563
+
564
+ for param_desc in params_array
565
+ if !param_desc.respond_to?(:required)
566
+ # pp param_desc
567
+ raise ("unexpected param_desc format")
568
+ end
569
+
570
+ required_params.push(param_desc.name.to_sym) if param_desc.required
571
+
572
+ param_type = swagger_param_type(param_desc)
573
+
574
+ if param_type == "object" && param_desc.validator.params_ordered
575
+ schema = json_schema_obj_from_params_array(param_desc.validator.params_ordered, allow_nulls)
576
+ if param_desc.additional_properties
577
+ schema[:additionalProperties] = true
578
+ end
579
+
580
+ if param_desc.is_array?
581
+ new_schema = {
582
+ type: 'array',
583
+ items: schema
584
+ }
585
+ schema = new_schema
586
+ end
587
+
588
+ if allow_nulls
589
+ # ideally we would write schema[:type] = ["object", "null"]
590
+ # but due to a bug in the json-schema gem, we need to use anyOf
591
+ # see https://github.com/ruby-json-schema/json-schema/issues/404
592
+ new_schema = {
593
+ anyOf: [schema, {type: "null"}]
594
+ }
595
+ schema = new_schema
596
+ end
597
+ param_defs[param_desc.name.to_sym] = schema if !schema.nil?
598
+ else
599
+ param_defs[param_desc.name.to_sym] = swagger_atomic_param(param_desc, true, nil, allow_nulls)
600
+ end
601
+ end
602
+
603
+ [param_defs, required_params]
604
+ end
605
+
606
+
607
+
608
+ #--------------------------------------------------------------------------
609
+ # swagger "Params" block generation
610
+ #--------------------------------------------------------------------------
611
+
612
+ def body_allowed_for_current_method
613
+ !(['get', 'head'].include?(@current_http_method))
614
+ end
615
+
616
+ def swagger_params_array_for_method(method, path)
617
+
618
+ swagger_result = []
619
+ all_params_hash = add_missing_params(method, path)
620
+
621
+ body_param_defs_array = all_params_hash.map {|k, v| v if !param_names_from_path(path).include?(k)}.select{|v| !v.nil?}
622
+ body_param_defs_hash = all_params_hash.select {|k, v| v if !param_names_from_path(path).include?(k)}
623
+ path_param_defs_hash = all_params_hash.select {|k, v| v if param_names_from_path(path).include?(k)}
624
+
625
+ path_param_defs_hash.each{|name,desc| desc.required = true}
626
+ add_params_from_hash(swagger_result, path_param_defs_hash, nil, "path")
627
+
628
+ if params_in_body? && body_allowed_for_current_method
629
+ if params_in_body_use_reference?
630
+ swagger_schema_for_body = {"$ref" => gen_referenced_block_from_params_array("#{swagger_op_id_for_method(method)}_input", body_param_defs_array)}
631
+ else
632
+ swagger_schema_for_body = json_schema_obj_from_params_array(body_param_defs_array)
633
+ end
634
+
635
+ swagger_body_param = {
636
+ name: 'body',
637
+ in: 'body',
638
+ schema: swagger_schema_for_body
639
+ }
640
+ swagger_result.push(swagger_body_param) if !swagger_schema_for_body.nil?
641
+
642
+ else
643
+ add_params_from_hash(swagger_result, body_param_defs_hash)
644
+ end
645
+
646
+ add_headers_from_hash(swagger_result, method.headers) if method.headers.present?
647
+
648
+ swagger_result
649
+ end
650
+
651
+
652
+ def add_headers_from_hash(swagger_params_array, headers)
653
+ swagger_headers = headers.map do |header|
654
+ {
655
+ name: header[:name],
656
+ in: 'header',
657
+ required: header[:options][:required],
658
+ description: header[:description],
659
+ type: header[:options][:type] || 'string'
660
+ }
661
+
662
+ end
663
+ swagger_params_array.push(*swagger_headers)
664
+ end
665
+
666
+
667
+ def add_params_from_hash(swagger_params_array, param_defs, prefix=nil, default_value_for_in=nil)
668
+
669
+ if default_value_for_in
670
+ @default_value_for_param_in = default_value_for_in
671
+ else
672
+ if body_allowed_for_current_method
673
+ @default_value_for_param_in = "formData"
674
+ else
675
+ @default_value_for_param_in = "query"
676
+ end
677
+ end
678
+
679
+
680
+ param_defs.each do |name, desc|
681
+
682
+ if !prefix.nil?
683
+ name = "#{prefix}[#{name}]"
684
+ end
685
+
686
+ if swagger_param_type(desc) == "object"
687
+ if desc.validator.params_ordered
688
+ params_hash = Hash[desc.validator.params_ordered.map {|desc| [desc.name, desc]}]
689
+ add_params_from_hash(swagger_params_array, params_hash, name)
690
+ else
691
+ warn_param_ignored_in_form_data(desc.name)
692
+ end
693
+ else
694
+ param_entry = swagger_atomic_param(desc, false, name, false)
695
+ if param_entry[:required]
696
+ swagger_params_array.unshift(param_entry)
697
+ else
698
+ swagger_params_array.push(param_entry)
699
+ end
700
+
701
+ end
702
+ end
703
+ end
704
+
705
+ end
706
+
707
+ end