apipie-rails 0.9.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rubocop.yml +2 -2
  3. data/.rubocop.yml +23 -14
  4. data/.rubocop_todo.yml +103 -487
  5. data/CHANGELOG.md +20 -3
  6. data/README.rst +12 -12
  7. data/app/controllers/apipie/apipies_controller.rb +6 -6
  8. data/app/helpers/apipie_helper.rb +1 -1
  9. data/lib/apipie/apipie_module.rb +5 -5
  10. data/lib/apipie/application.rb +81 -55
  11. data/lib/apipie/configuration.rb +19 -26
  12. data/lib/apipie/dsl_definition.rb +8 -9
  13. data/lib/apipie/error_description.rb +1 -1
  14. data/lib/apipie/errors.rb +2 -16
  15. data/lib/apipie/extractor/collector.rb +3 -3
  16. data/lib/apipie/extractor/recorder.rb +1 -1
  17. data/lib/apipie/extractor.rb +2 -2
  18. data/lib/apipie/generator/config.rb +12 -0
  19. data/lib/apipie/generator/swagger/computed_interface_id.rb +23 -0
  20. data/lib/apipie/generator/swagger/config.rb +78 -0
  21. data/lib/apipie/generator/swagger/context.rb +12 -1
  22. data/lib/apipie/generator/swagger/method_description/api_decorator.rb +20 -0
  23. data/lib/apipie/generator/swagger/method_description/api_schema_service.rb +86 -0
  24. data/lib/apipie/generator/swagger/method_description/decorator.rb +22 -0
  25. data/lib/apipie/generator/swagger/method_description/parameters_service.rb +139 -0
  26. data/lib/apipie/generator/swagger/method_description/response_schema_service.rb +46 -0
  27. data/lib/apipie/generator/swagger/method_description/response_service.rb +58 -0
  28. data/lib/apipie/generator/swagger/method_description.rb +2 -0
  29. data/lib/apipie/generator/swagger/operation_id.rb +2 -2
  30. data/lib/apipie/generator/swagger/param_description/builder.rb +4 -4
  31. data/lib/apipie/generator/swagger/param_description/composite.rb +9 -1
  32. data/lib/apipie/generator/swagger/param_description/in.rb +1 -1
  33. data/lib/apipie/generator/swagger/param_description/path_params_composite.rb +61 -0
  34. data/lib/apipie/generator/swagger/param_description/referenced_composite.rb +36 -0
  35. data/lib/apipie/generator/swagger/param_description/type.rb +9 -2
  36. data/lib/apipie/generator/swagger/path_decorator.rb +36 -0
  37. data/lib/apipie/generator/swagger/referenced_definitions.rb +17 -0
  38. data/lib/apipie/generator/swagger/resource_description_collection.rb +30 -0
  39. data/lib/apipie/generator/swagger/resource_description_composite.rb +56 -0
  40. data/lib/apipie/generator/swagger/schema.rb +63 -0
  41. data/lib/apipie/generator/swagger/type_extractor.rb +0 -19
  42. data/lib/apipie/generator/swagger/warning.rb +3 -6
  43. data/lib/apipie/generator/swagger/warning_writer.rb +7 -1
  44. data/lib/apipie/helpers.rb +3 -3
  45. data/lib/apipie/method_description.rb +5 -3
  46. data/lib/apipie/param_description.rb +4 -2
  47. data/lib/apipie/resource_description.rb +11 -8
  48. data/lib/apipie/response_description.rb +1 -1
  49. data/lib/apipie/response_description_adapter.rb +3 -3
  50. data/lib/apipie/routing.rb +1 -1
  51. data/lib/apipie/rspec/response_validation_helper.rb +1 -1
  52. data/lib/apipie/swagger_generator.rb +27 -551
  53. data/lib/apipie/validator.rb +9 -5
  54. data/lib/apipie/version.rb +1 -1
  55. data/lib/apipie-rails.rb +17 -0
  56. data/lib/tasks/apipie.rake +25 -20
  57. data/spec/controllers/api/v2/nested/resources_controller_spec.rb +2 -2
  58. data/spec/controllers/pets_controller_spec.rb +10 -16
  59. data/spec/controllers/users_controller_spec.rb +2 -2
  60. data/spec/dummy/app/controllers/pets_controller.rb +4 -4
  61. data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +2 -2
  62. data/spec/dummy/app/controllers/twitter_example_controller.rb +2 -2
  63. data/spec/dummy/app/controllers/users_controller.rb +5 -5
  64. data/spec/dummy/config.ru +1 -1
  65. data/spec/lib/apipie/apipies_controller_spec.rb +4 -0
  66. data/spec/lib/apipie/application_spec.rb +25 -15
  67. data/spec/lib/apipie/configuration_spec.rb +15 -0
  68. data/spec/lib/apipie/generator/swagger/config_spec.rb +19 -0
  69. data/spec/lib/apipie/generator/swagger/context_spec.rb +23 -2
  70. data/spec/lib/apipie/generator/swagger/method_description/api_schema_service_spec.rb +106 -0
  71. data/spec/lib/apipie/generator/swagger/method_description/response_schema_service_spec.rb +105 -0
  72. data/spec/lib/apipie/generator/swagger/param_description/builder_spec.rb +1 -1
  73. data/spec/lib/apipie/generator/swagger/param_description/composite_spec.rb +2 -2
  74. data/spec/lib/apipie/generator/swagger/param_description/type_spec.rb +7 -7
  75. data/spec/lib/apipie/generator/swagger/path_decorator_spec.rb +57 -0
  76. data/spec/lib/apipie/generator/swagger/referenced_definitions_spec.rb +35 -0
  77. data/spec/lib/apipie/generator/swagger/resource_description_composite_spec.rb +37 -0
  78. data/spec/lib/apipie/generator/swagger/resource_descriptions_collection_spec.rb +57 -0
  79. data/spec/lib/apipie/generator/swagger/schema_spec.rb +89 -0
  80. data/spec/lib/apipie/generator/swagger/type_extractor_spec.rb +0 -43
  81. data/spec/lib/apipie/generator/swagger/warning_spec.rb +1 -1
  82. data/spec/lib/apipie/generator/swagger/warning_writer_spec.rb +19 -7
  83. data/spec/lib/apipie/method_description_spec.rb +101 -66
  84. data/spec/lib/apipie/no_documented_method_spec.rb +17 -0
  85. data/spec/lib/apipie/param_description_spec.rb +209 -49
  86. data/spec/lib/apipie/param_group_spec.rb +1 -0
  87. data/spec/lib/apipie/resource_description_spec.rb +71 -28
  88. data/spec/lib/apipie/response_does_not_match_swagger_schema_spec.rb +35 -0
  89. data/spec/lib/apipie/swagger_generator_spec.rb +94 -0
  90. data/spec/lib/apipie/validator_spec.rb +47 -11
  91. data/spec/lib/rake_spec.rb +1 -1
  92. data/spec/lib/swagger/rake_swagger_spec.rb +6 -6
  93. data/spec/lib/swagger/swagger_dsl_spec.rb +17 -11
  94. data/spec/lib/validators/array_validator_spec.rb +1 -1
  95. data/spec/spec_helper.rb +2 -2
  96. metadata +31 -3
data/lib/apipie/errors.rb CHANGED
@@ -60,27 +60,13 @@ module Apipie
60
60
 
61
61
  class ResponseDoesNotMatchSwaggerSchema < Error
62
62
  def initialize(controller_name, method_name, response_code, error_messages, schema, returned_object)
63
- @controller_name = controller_name
64
- @method_name = method_name
65
- @response_code = response_code
66
- @error_messages = error_messages
67
- @schema = schema
68
- @returned_object = returned_object
69
- end
70
-
71
- def to_s
72
- "Response does not match swagger schema (#{@controller_name}##{@method_name} #{@response_code}): #{@error_messages}\nSchema: #{JSON(@schema)}\nReturned object: #{@returned_object}"
63
+ super("Response does not match swagger schema (#{controller_name}##{method_name} #{response_code}): #{error_messages}\nSchema: #{JSON(schema)}\nReturned object: #{returned_object}")
73
64
  end
74
65
  end
75
66
 
76
67
  class NoDocumentedMethod < Error
77
68
  def initialize(controller_name, method_name)
78
- @method_name = method_name
79
- @controller_name = controller_name
80
- end
81
-
82
- def to_s
83
- "There is no documented method #{@controller_name}##{@method_name}"
69
+ super("There is no documented method #{controller_name}##{method_name}")
84
70
  end
85
71
  end
86
72
  end
@@ -19,7 +19,7 @@ module Apipie
19
19
  def ignore_call?(record)
20
20
  return true unless record[:controller]
21
21
  return true if @ignored.include?(record[:controller].name)
22
- return true if @ignored.include?("#{Apipie.get_resource_name(record[:controller].name)}##{record[:action]}")
22
+ return true if @ignored.include?("#{Apipie.resource_id(record[:controller].name)}##{record[:action]}")
23
23
  return true unless @api_controllers_paths.include?(controller_full_path(record[:controller]))
24
24
  end
25
25
 
@@ -33,7 +33,7 @@ module Apipie
33
33
  end
34
34
 
35
35
  def add_to_records(record)
36
- key = "#{Apipie.get_resource_name(record[:controller])}##{record[:action]}"
36
+ key = "#{Apipie.get_resource_id(record[:controller])}##{record[:action]}"
37
37
  @records[key] << record
38
38
  end
39
39
 
@@ -96,7 +96,7 @@ module Apipie
96
96
  end
97
97
 
98
98
  def add_routes_info(desc)
99
- api_prefix = Apipie.api_base_url.sub(/\/$/,"")
99
+ api_prefix = Apipie.api_base_url.sub(%r{/$},"")
100
100
  desc[:api] = Apipie::Extractor.apis_from_routes[[desc[:controller].name, desc[:action]]]
101
101
  if desc[:api]
102
102
  desc[:params].each do |name, param|
@@ -9,7 +9,7 @@ module Apipie
9
9
 
10
10
  def analyse_env(env)
11
11
  @verb = env["REQUEST_METHOD"].to_sym
12
- @path = env["PATH_INFO"].sub(/^\/*/,"/")
12
+ @path = env["PATH_INFO"].sub(%r{^/*},"/")
13
13
  @query = env["QUERY_STRING"] unless env["QUERY_STRING"].blank?
14
14
  @params = Rack::Utils.parse_nested_query(@query)
15
15
  @params.merge!(env["action_dispatch.request.request_parameters"] || {})
@@ -81,7 +81,7 @@ module Apipie
81
81
  def apis_from_routes
82
82
  return @apis_from_routes if @apis_from_routes
83
83
 
84
- @api_prefix = Apipie.api_base_url.sub(/\/$/,"")
84
+ @api_prefix = Apipie.api_base_url.sub(%r{/$},"")
85
85
  populate_api_routes
86
86
  update_api_descriptions
87
87
 
@@ -154,7 +154,7 @@ module Apipie
154
154
  def update_api_descriptions
155
155
  apis_from_docs = all_apis_from_docs
156
156
  @apis_from_routes.each do |(controller, action), new_apis|
157
- method_key = "#{Apipie.get_resource_name(controller.safe_constantize || next)}##{action}"
157
+ method_key = "#{Apipie.get_resource_id(controller.safe_constantize || next)}##{action}"
158
158
  old_apis = apis_from_docs[method_key] || []
159
159
  new_apis.each do |new_api|
160
160
  new_api[:path]&.sub!(/\(\.:format\)$/,"")
@@ -0,0 +1,12 @@
1
+ module Apipie
2
+ module Generator
3
+ # Configuration interface for generators
4
+ class Config
5
+ include Singleton
6
+
7
+ def swagger
8
+ Apipie::Generator::Swagger::Config.instance
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ # The {Apipie::Generator::Swagger::ComputedInterfaceId.id} is a number that is
2
+ # uniquely derived from the list of operations added to the swagger definition (in an order-dependent way).
3
+ # it can be used for regression testing, allowing some differentiation between changes that
4
+ # result from changes to the input and those that result from changes to the generation
5
+ # algorithms.
6
+ #
7
+ # @note At the moment, this only takes operation ids into account, and ignores
8
+ # parameter definitions, so it's only partially useful.
9
+ class Apipie::Generator::Swagger::ComputedInterfaceId
10
+ include Singleton
11
+
12
+ def initialize
13
+ @computed_interface_id = 0
14
+ end
15
+
16
+ def add!(operation_id)
17
+ @computed_interface_id = Zlib.crc32("#{@computed_interface_id} #{operation_id}")
18
+ end
19
+
20
+ def id
21
+ @computed_interface_id
22
+ end
23
+ end
@@ -0,0 +1,78 @@
1
+ require 'singleton'
2
+
3
+ module Apipie
4
+ module Generator
5
+ module Swagger
6
+ class Config
7
+ include Singleton
8
+
9
+ CONFIG_ATTRIBUTES = [:include_warning_tags, :content_type_input,
10
+ :json_input_uses_refs, :suppress_warnings, :api_host,
11
+ :generate_x_computed_id_field, :allow_additional_properties_in_response,
12
+ :responses_use_refs, :schemes, :security_definitions,
13
+ :global_security].freeze
14
+
15
+ attr_accessor(*CONFIG_ATTRIBUTES)
16
+
17
+ CONFIG_ATTRIBUTES.each do |attribute|
18
+ old_setter_method = "swagger_#{attribute}="
19
+ define_method(old_setter_method) do |value|
20
+ ActiveSupport::Deprecation.warn(
21
+ <<~HEREDOC
22
+ config.#{old_setter_method}#{value} is deprecated.
23
+ config.generator.swagger.#{attribute} instead.
24
+ HEREDOC
25
+ )
26
+
27
+ send("#{attribute}=", value)
28
+ end
29
+
30
+ old_setter_method = "swagger_#{attribute}"
31
+ define_method(old_setter_method) do
32
+ ActiveSupport::Deprecation.warn(
33
+ <<~HEREDOC
34
+ config.#{old_setter_method} is deprecated.
35
+ Use config.generator.swagger.#{attribute} instead.
36
+ HEREDOC
37
+ )
38
+
39
+ send(attribute)
40
+ end
41
+ end
42
+
43
+ alias include_warning_tags? include_warning_tags
44
+ alias json_input_uses_refs? json_input_uses_refs
45
+ alias responses_use_refs? responses_use_refs
46
+ alias generate_x_computed_id_field? generate_x_computed_id_field
47
+ alias swagger_include_warning_tags? swagger_include_warning_tags
48
+ alias swagger_json_input_uses_refs? swagger_json_input_uses_refs
49
+ alias swagger_responses_use_refs? swagger_responses_use_refs
50
+ alias swagger_generate_x_computed_id_field? swagger_generate_x_computed_id_field
51
+
52
+ def initialize
53
+ @content_type_input = :form_data # this can be :json or :form_data
54
+ @json_input_uses_refs = false
55
+ @include_warning_tags = false
56
+ @suppress_warnings = false # [105,100,102]
57
+ @api_host = 'localhost:3000'
58
+ @generate_x_computed_id_field = false
59
+ @allow_additional_properties_in_response = false
60
+ @responses_use_refs = true
61
+ @schemes = [:https]
62
+ @security_definitions = {}
63
+ @global_security = []
64
+ end
65
+
66
+ def self.deprecated_methods
67
+ CONFIG_ATTRIBUTES.map do |attribute|
68
+ [
69
+ :"swagger_#{attribute}=",
70
+ :"swagger_#{attribute}?",
71
+ :"swagger_#{attribute}"
72
+ ]
73
+ end.flatten
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,10 +1,12 @@
1
1
  class Apipie::Generator::Swagger::Context
2
- attr_reader :default_in_value, :language, :http_method, :controller_method
2
+ attr_reader :default_in_value, :language, :http_method, :controller_method,
3
+ :prefix
3
4
 
4
5
  def initialize(
5
6
  allow_null:,
6
7
  http_method:,
7
8
  controller_method:,
9
+ prefix: nil,
8
10
  default_in_value: nil,
9
11
  language: nil,
10
12
  in_schema: true
@@ -15,6 +17,7 @@ class Apipie::Generator::Swagger::Context
15
17
  @in_schema = in_schema
16
18
  @http_method = http_method
17
19
  @controller_method = controller_method
20
+ @prefix = prefix
18
21
  end
19
22
 
20
23
  def allow_null?
@@ -24,4 +27,12 @@ class Apipie::Generator::Swagger::Context
24
27
  def in_schema?
25
28
  @in_schema == true
26
29
  end
30
+
31
+ def add_to_prefix!(prefix)
32
+ @prefix = if @prefix.present?
33
+ "#{@prefix}[#{prefix}]"
34
+ else
35
+ prefix
36
+ end
37
+ end
27
38
  end
@@ -0,0 +1,20 @@
1
+ class Apipie::Generator::Swagger::MethodDescription::ApiDecorator < SimpleDelegator
2
+ def normalized_http_method
3
+ @normalized_http_method ||= http_method.downcase
4
+ end
5
+
6
+ def summary(method_description:, language:)
7
+ s = Apipie.app.translate(short_description, language)
8
+
9
+ if s.blank?
10
+ Apipie::Generator::Swagger::Warning.for_code(
11
+ Apipie::Generator::Swagger::Warning::MISSING_METHOD_SUMMARY_CODE,
12
+ method_description.ruby_name
13
+ ).warn_through_writer
14
+
15
+ nil
16
+ else
17
+ s
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,86 @@
1
+ class Apipie::Generator::Swagger::MethodDescription::ApiSchemaService
2
+ # @param [Apipie::Generator::Swagger::MethodDescription::Decorator] method_description
3
+ def initialize(method_description, language: nil)
4
+ @method_description = method_description
5
+ @language = language
6
+ end
7
+
8
+ # @return [Hash]
9
+ def call
10
+ @method_description.apis.each_with_object({}) do |api, paths|
11
+ api = Apipie::Generator::Swagger::MethodDescription::ApiDecorator.new(api)
12
+ path = Apipie::Generator::Swagger::PathDecorator.new(api.path)
13
+ op_id = Apipie::Generator::Swagger::OperationId.from(api).to_s
14
+
15
+ if Apipie.configuration.generator.swagger.generate_x_computed_id_field?
16
+ Apipie::Generator::Swagger::ComputedInterfaceId.instance.add!(op_id)
17
+ end
18
+
19
+ parameters = Apipie::Generator::Swagger::MethodDescription::ParametersService
20
+ .new(@method_description, path: path, http_method: api.normalized_http_method)
21
+ .call
22
+
23
+ paths[path.swagger_path(@method_description)] ||= {}
24
+ paths[path.swagger_path(@method_description)][api.normalized_http_method] = {
25
+ tags: tags,
26
+ consumes: consumes,
27
+ operationId: op_id,
28
+ summary: api.summary(method_description: @method_description, language: @language),
29
+ parameters: parameters,
30
+ responses: responses(api),
31
+ description: Apipie.app.translate(@method_description.full_description, @language)
32
+ }.compact
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def summary(api)
39
+ translated_description = Apipie.app.translate(api.short_description, @language)
40
+
41
+ return translated_description if translated_description.present?
42
+
43
+ Apipie::Generator::Swagger::Warning.for_code(
44
+ Apipie::Generator::Swagger::Warning::MISSING_METHOD_SUMMARY_CODE,
45
+ @method_description.ruby_name
46
+ ).warn_through_writer
47
+ end
48
+
49
+ def tags
50
+ [@method_description.resource._id] +
51
+ warning_tags +
52
+ @method_description.tag_list.tags
53
+ end
54
+
55
+ def warning_tags
56
+ if Apipie.configuration.generator.swagger.include_warning_tags? &&
57
+ Apipie::Generator::Swagger::WarningWriter.instance.issued_warnings?
58
+ ['warnings issued']
59
+ else
60
+ []
61
+ end
62
+ end
63
+
64
+ def consumes
65
+ if params_in_body?
66
+ ['application/json']
67
+ else
68
+ ['application/x-www-form-urlencoded', 'multipart/form-data']
69
+ end
70
+ end
71
+
72
+ def params_in_body?
73
+ Apipie.configuration.generator.swagger.content_type_input == :json
74
+ end
75
+
76
+ # @param [Apipie::Generator::Swagger::MethodDescription::ApiDecorator] api
77
+ def responses(api)
78
+ Apipie::Generator::Swagger::MethodDescription::ResponseService
79
+ .new(
80
+ @method_description,
81
+ language: @language,
82
+ http_method: api.normalized_http_method
83
+ )
84
+ .call
85
+ end
86
+ end
@@ -0,0 +1,22 @@
1
+ class Apipie::Generator::Swagger::MethodDescription::Decorator < SimpleDelegator
2
+ # @return [String]
3
+ def operation_id
4
+ "#{object.resource.controller.name}__#{object.method_name}"
5
+ end
6
+
7
+ # @return [String]
8
+ def ruby_name
9
+ if object.blank?
10
+ '<no method>'
11
+ else
12
+ "#{object.resource.controller.name}##{object.method_name}"
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ # @return [Apipie::MethodDescription, nil]
19
+ def object
20
+ __getobj__
21
+ end
22
+ end
@@ -0,0 +1,139 @@
1
+ class Apipie::Generator::Swagger::MethodDescription::ParametersService
2
+ # @param [Apipie::Generator::Swagger::MethodDescription::Decorator] method_description
3
+ # @param [Apipie::Generator::Swagger::PathDecorator] path
4
+ # @param [Symbol] http_method
5
+ def initialize(method_description, path:, http_method:)
6
+ @method_description = method_description
7
+ @path = path
8
+ @http_method = http_method
9
+ end
10
+
11
+ # @return [Array]
12
+ def call
13
+ path_params_schema + body_params_schema + header_params_schema
14
+ end
15
+
16
+ private
17
+
18
+ def path_params_schema
19
+ Apipie::Generator::Swagger::ParamDescription::PathParamsComposite.new(
20
+ path_param_descriptions,
21
+ Apipie::Generator::Swagger::Context.new(
22
+ allow_null: false,
23
+ default_in_value: 'path',
24
+ http_method: @http_method,
25
+ controller_method: @method_description
26
+ )
27
+ ).to_swagger
28
+ end
29
+
30
+ def body_params_schema
31
+ if params_in_body? && body_allowed_for_current_method?
32
+ composite = Apipie::Generator::Swagger::ParamDescription::Composite.new(
33
+ body_param_descriptions,
34
+ Apipie::Generator::Swagger::Context.new(
35
+ allow_null: false,
36
+ http_method: @http_method,
37
+ controller_method: @method_description
38
+ )
39
+ )
40
+
41
+ if Apipie.configuration.generator.swagger.json_input_uses_refs?
42
+ composite = composite
43
+ .referenced("#{@method_description.operation_id}_input")
44
+ end
45
+
46
+ swagger_schema_for_body = composite.to_swagger
47
+
48
+ swagger_body_param = {
49
+ name: 'body',
50
+ in: 'body',
51
+ schema: swagger_schema_for_body
52
+ }
53
+
54
+ if swagger_schema_for_body.present?
55
+ [swagger_body_param]
56
+ else
57
+ []
58
+ end
59
+ else
60
+ Apipie::Generator::Swagger::ParamDescription::PathParamsComposite.new(
61
+ body_param_descriptions,
62
+ Apipie::Generator::Swagger::Context.new(
63
+ allow_null: false,
64
+ http_method: @http_method,
65
+ controller_method: @method_description
66
+ )
67
+ ).to_swagger
68
+ end
69
+ end
70
+
71
+ def all_params
72
+ @all_params ||=
73
+ begin
74
+ param_names_from_method = @method_description.params.keys
75
+ missing = @path.param_names - param_names_from_method
76
+
77
+ result = @method_description.params
78
+
79
+ missing.each do |name|
80
+ warn_path_parameter_not_described(name, @path)
81
+
82
+ result[name.to_sym] = Apipie::Generator::Swagger::ParamDescription
83
+ .create_for_missing_param(@method_description, name)
84
+ end
85
+
86
+ result
87
+ end
88
+ end
89
+
90
+ def body_param_descriptions
91
+ @body_param_descriptions ||= all_params
92
+ .reject { |k, _| @path.param?(k) }
93
+ .values
94
+ end
95
+
96
+ def path_param_descriptions
97
+ @path_param_descriptions ||= all_params
98
+ .select { |k, _| @path.param?(k) }
99
+ .each { |_, desc| desc.required = true }
100
+ .values
101
+ end
102
+
103
+ # @return [Array]
104
+ def header_params_schema
105
+ return [] if @method_description.headers.blank?
106
+
107
+ @method_description.headers.map do |header|
108
+ header_hash = {
109
+ name: header[:name],
110
+ in: 'header',
111
+ required: header[:options][:required],
112
+ description: header[:description],
113
+ type: header[:options][:type] || 'string'
114
+
115
+ }
116
+ if header[:options][:default]
117
+ header_hash[:default] = header[:options][:default]
118
+ end
119
+
120
+ header_hash
121
+ end
122
+ end
123
+
124
+ def params_in_body?
125
+ Apipie.configuration.generator.swagger.content_type_input == :json
126
+ end
127
+
128
+ def body_allowed_for_current_method?
129
+ %w[get head].exclude?(@http_method)
130
+ end
131
+
132
+ def warn_path_parameter_not_described(name, path)
133
+ Apipie::Generator::Swagger::Warning.for_code(
134
+ Apipie::Generator::Swagger::Warning::PATH_PARAM_NOT_DESCRIBED_CODE,
135
+ @method_description.ruby_name,
136
+ { name: name, path: path }
137
+ ).warn_through_writer
138
+ end
139
+ end
@@ -0,0 +1,46 @@
1
+ class Apipie::Generator::Swagger::MethodDescription::ResponseSchemaService
2
+ # @param [Apipie::ResponseDescription, Apipie::ResponseDescriptionAdapter] response_description
3
+ def initialize(response_description, allow_null:, http_method:, controller_method:)
4
+ @response_description = response_description
5
+ @allow_null = allow_null
6
+ @http_method = http_method
7
+ @controller_method = controller_method
8
+ end
9
+
10
+ def to_swagger
11
+ composite = Apipie::Generator::Swagger::ParamDescription::Composite.new(
12
+ @response_description.params_ordered,
13
+ Apipie::Generator::Swagger::Context.new(
14
+ allow_null: @allow_null,
15
+ http_method: @http_method,
16
+ controller_method: @controller_method
17
+ )
18
+ )
19
+
20
+ if Apipie.configuration.generator.swagger.responses_use_refs? && @response_description.typename.present?
21
+ composite = composite.referenced(@response_description.typename)
22
+ end
23
+
24
+ schema = composite.to_swagger
25
+
26
+ if @response_description.is_array? && schema
27
+ schema = { type: type_for_array, items: schema }
28
+ end
29
+
30
+ if @response_description.allow_additional_properties
31
+ schema[:additionalProperties] = true
32
+ end
33
+
34
+ schema
35
+ end
36
+
37
+ private
38
+
39
+ def type_for_array
40
+ if @allow_null == true
41
+ %w[array null]
42
+ else
43
+ 'array'
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,58 @@
1
+ class Apipie::Generator::Swagger::MethodDescription::ResponseService
2
+ # @param [Apipie::Generator::Swagger::MethodDescription::Decorator] method_description
3
+ # @param [Symbol] http_method
4
+ def initialize(method_description, http_method:, language:)
5
+ @method_description = method_description
6
+ @http_method = http_method
7
+ @language = language
8
+ end
9
+
10
+ # @return [Hash]
11
+ def call
12
+ result = {}
13
+ result.merge!(errors)
14
+ result.merge!(responses)
15
+ result.merge!(empty_returns)
16
+
17
+ result
18
+ end
19
+
20
+ private
21
+
22
+ # @return [Hash]
23
+ def errors
24
+ @errors ||= @method_description.errors.each_with_object({}) do |error, errors|
25
+ errors[error.code] = {
26
+ description: Apipie.app.translate(error.description, @language)
27
+ }
28
+ end
29
+ end
30
+
31
+ # @return [Hash]
32
+ def responses
33
+ @responses ||=
34
+ @method_description.returns.each_with_object({}) do |response, responses_schema|
35
+ responses_schema[response.code] = {
36
+ description: Apipie.app.translate(response.description, @language),
37
+ schema: Apipie::Generator::Swagger::MethodDescription::ResponseSchemaService.new(
38
+ response,
39
+ allow_null: false,
40
+ http_method: @http_method,
41
+ controller_method: @method_description
42
+ ).to_swagger
43
+ }.compact
44
+ end
45
+ end
46
+
47
+ # @return [Hash]
48
+ def empty_returns
49
+ return {} if errors.present? || responses.present?
50
+
51
+ Apipie::Generator::Swagger::Warning.for_code(
52
+ Apipie::Generator::Swagger::Warning::NO_RETURN_CODES_SPECIFIED_CODE,
53
+ @method_description.ruby_name
54
+ ).warn_through_writer
55
+
56
+ { 200 => { description: 'ok' } }
57
+ end
58
+ end
@@ -0,0 +1,2 @@
1
+ module Apipie::Generator::Swagger::MethodDescription
2
+ end
@@ -22,7 +22,7 @@ class Apipie::Generator::Swagger::OperationId
22
22
  # @return [Apipie::Generator::Swagger::OperationId]
23
23
  def self.from(describable, param: nil)
24
24
  path, http_method =
25
- if describable.is_a?(Apipie::MethodDescription::Api)
25
+ if describable.respond_to?(:path) && describable.respond_to?(:http_method)
26
26
  [describable.path, describable.http_method]
27
27
  elsif describable.is_a?(Apipie::MethodDescription)
28
28
  [describable.apis.first.path, describable.apis.first.http_method]
@@ -37,7 +37,7 @@ class Apipie::Generator::Swagger::OperationId
37
37
  #
38
38
  # @return [String]
39
39
  def path
40
- @path.gsub(/\//, '_').gsub(/:(\w+)/, '\1').gsub(/_$/, '')
40
+ @path.gsub(%r{/}, '_').gsub(/:(\w+)/, '\1').gsub(/_$/, '')
41
41
  end
42
42
 
43
43
  # Converts an http method like `GET` to `get` Using lowercase http method,
@@ -1,7 +1,7 @@
1
1
  class Apipie::Generator::Swagger::ParamDescription::Builder
2
2
  # @param [Apipie::ParamDescription] param_description
3
3
  # @param [TrueClass, FalseClass] in_schema
4
- # @param [String] controller_method
4
+ # @param [Apipie::MethodDescription] controller_method
5
5
  def initialize(param_description, in_schema:, controller_method:)
6
6
  @param_description = param_description
7
7
  @in_schema = in_schema
@@ -88,16 +88,16 @@ class Apipie::Generator::Swagger::ParamDescription::Builder
88
88
 
89
89
  def warn_optional_without_default_value(definition)
90
90
  if !required? && !definition.key?(:default)
91
- method =
91
+ method_id =
92
92
  if @param_description.is_a?(Apipie::ResponseDescriptionAdapter::PropDesc)
93
93
  @controller_method
94
94
  else
95
- @param_description.method_description.method
95
+ Apipie::Generator::Swagger::MethodDescription::Decorator.new(@controller_method).ruby_name
96
96
  end
97
97
 
98
98
  Apipie::Generator::Swagger::Warning.for_code(
99
99
  Apipie::Generator::Swagger::Warning::OPTIONAL_WITHOUT_DEFAULT_VALUE_CODE,
100
- method,
100
+ method_id,
101
101
  { parameter: @param_description.name }
102
102
  ).warn_through_writer
103
103
  end