apipie-rails 0.9.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rubocop.yml +2 -2
- data/.rubocop.yml +23 -14
- data/.rubocop_todo.yml +103 -487
- data/CHANGELOG.md +20 -3
- data/README.rst +12 -12
- data/app/controllers/apipie/apipies_controller.rb +6 -6
- data/app/helpers/apipie_helper.rb +1 -1
- data/lib/apipie/apipie_module.rb +5 -5
- data/lib/apipie/application.rb +81 -55
- data/lib/apipie/configuration.rb +19 -26
- data/lib/apipie/dsl_definition.rb +8 -9
- data/lib/apipie/error_description.rb +1 -1
- data/lib/apipie/errors.rb +2 -16
- data/lib/apipie/extractor/collector.rb +3 -3
- data/lib/apipie/extractor/recorder.rb +1 -1
- data/lib/apipie/extractor.rb +2 -2
- data/lib/apipie/generator/config.rb +12 -0
- data/lib/apipie/generator/swagger/computed_interface_id.rb +23 -0
- data/lib/apipie/generator/swagger/config.rb +78 -0
- data/lib/apipie/generator/swagger/context.rb +12 -1
- data/lib/apipie/generator/swagger/method_description/api_decorator.rb +20 -0
- data/lib/apipie/generator/swagger/method_description/api_schema_service.rb +86 -0
- data/lib/apipie/generator/swagger/method_description/decorator.rb +22 -0
- data/lib/apipie/generator/swagger/method_description/parameters_service.rb +139 -0
- data/lib/apipie/generator/swagger/method_description/response_schema_service.rb +46 -0
- data/lib/apipie/generator/swagger/method_description/response_service.rb +58 -0
- data/lib/apipie/generator/swagger/method_description.rb +2 -0
- data/lib/apipie/generator/swagger/operation_id.rb +2 -2
- data/lib/apipie/generator/swagger/param_description/builder.rb +4 -4
- data/lib/apipie/generator/swagger/param_description/composite.rb +9 -1
- data/lib/apipie/generator/swagger/param_description/in.rb +1 -1
- data/lib/apipie/generator/swagger/param_description/path_params_composite.rb +61 -0
- data/lib/apipie/generator/swagger/param_description/referenced_composite.rb +36 -0
- data/lib/apipie/generator/swagger/param_description/type.rb +9 -2
- data/lib/apipie/generator/swagger/path_decorator.rb +36 -0
- data/lib/apipie/generator/swagger/referenced_definitions.rb +17 -0
- data/lib/apipie/generator/swagger/resource_description_collection.rb +30 -0
- data/lib/apipie/generator/swagger/resource_description_composite.rb +56 -0
- data/lib/apipie/generator/swagger/schema.rb +63 -0
- data/lib/apipie/generator/swagger/type_extractor.rb +0 -19
- data/lib/apipie/generator/swagger/warning.rb +3 -6
- data/lib/apipie/generator/swagger/warning_writer.rb +7 -1
- data/lib/apipie/helpers.rb +3 -3
- data/lib/apipie/method_description.rb +5 -3
- data/lib/apipie/param_description.rb +4 -2
- data/lib/apipie/resource_description.rb +11 -8
- data/lib/apipie/response_description.rb +1 -1
- data/lib/apipie/response_description_adapter.rb +3 -3
- data/lib/apipie/routing.rb +1 -1
- data/lib/apipie/rspec/response_validation_helper.rb +1 -1
- data/lib/apipie/swagger_generator.rb +27 -551
- data/lib/apipie/validator.rb +9 -5
- data/lib/apipie/version.rb +1 -1
- data/lib/apipie-rails.rb +17 -0
- data/lib/tasks/apipie.rake +25 -20
- data/spec/controllers/api/v2/nested/resources_controller_spec.rb +2 -2
- data/spec/controllers/pets_controller_spec.rb +10 -16
- data/spec/controllers/users_controller_spec.rb +2 -2
- data/spec/dummy/app/controllers/pets_controller.rb +4 -4
- data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +2 -2
- data/spec/dummy/app/controllers/twitter_example_controller.rb +2 -2
- data/spec/dummy/app/controllers/users_controller.rb +5 -5
- data/spec/dummy/config.ru +1 -1
- data/spec/lib/apipie/apipies_controller_spec.rb +4 -0
- data/spec/lib/apipie/application_spec.rb +25 -15
- data/spec/lib/apipie/configuration_spec.rb +15 -0
- data/spec/lib/apipie/generator/swagger/config_spec.rb +19 -0
- data/spec/lib/apipie/generator/swagger/context_spec.rb +23 -2
- data/spec/lib/apipie/generator/swagger/method_description/api_schema_service_spec.rb +106 -0
- data/spec/lib/apipie/generator/swagger/method_description/response_schema_service_spec.rb +105 -0
- data/spec/lib/apipie/generator/swagger/param_description/builder_spec.rb +1 -1
- data/spec/lib/apipie/generator/swagger/param_description/composite_spec.rb +2 -2
- data/spec/lib/apipie/generator/swagger/param_description/type_spec.rb +7 -7
- data/spec/lib/apipie/generator/swagger/path_decorator_spec.rb +57 -0
- data/spec/lib/apipie/generator/swagger/referenced_definitions_spec.rb +35 -0
- data/spec/lib/apipie/generator/swagger/resource_description_composite_spec.rb +37 -0
- data/spec/lib/apipie/generator/swagger/resource_descriptions_collection_spec.rb +57 -0
- data/spec/lib/apipie/generator/swagger/schema_spec.rb +89 -0
- data/spec/lib/apipie/generator/swagger/type_extractor_spec.rb +0 -43
- data/spec/lib/apipie/generator/swagger/warning_spec.rb +1 -1
- data/spec/lib/apipie/generator/swagger/warning_writer_spec.rb +19 -7
- data/spec/lib/apipie/method_description_spec.rb +101 -66
- data/spec/lib/apipie/no_documented_method_spec.rb +17 -0
- data/spec/lib/apipie/param_description_spec.rb +209 -49
- data/spec/lib/apipie/param_group_spec.rb +1 -0
- data/spec/lib/apipie/resource_description_spec.rb +71 -28
- data/spec/lib/apipie/response_does_not_match_swagger_schema_spec.rb +35 -0
- data/spec/lib/apipie/swagger_generator_spec.rb +94 -0
- data/spec/lib/apipie/validator_spec.rb +47 -11
- data/spec/lib/rake_spec.rb +1 -1
- data/spec/lib/swagger/rake_swagger_spec.rb +6 -6
- data/spec/lib/swagger/swagger_dsl_spec.rb +17 -11
- data/spec/lib/validators/array_validator_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -2
- 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
|
-
|
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
|
-
|
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.
|
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.
|
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"] || {})
|
data/lib/apipie/extractor.rb
CHANGED
@@ -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.
|
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,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
|
@@ -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.
|
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(
|
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 [
|
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
|
-
|
91
|
+
method_id =
|
92
92
|
if @param_description.is_a?(Apipie::ResponseDescriptionAdapter::PropDesc)
|
93
93
|
@controller_method
|
94
94
|
else
|
95
|
-
@
|
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
|
-
|
100
|
+
method_id,
|
101
101
|
{ parameter: @param_description.name }
|
102
102
|
).warn_through_writer
|
103
103
|
end
|