grape-swagger 0.34.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +86 -0
- data/.travis.yml +19 -12
- data/CHANGELOG.md +47 -4
- data/Gemfile +9 -3
- data/README.md +125 -12
- data/UPGRADING.md +34 -0
- data/grape-swagger.gemspec +1 -2
- data/lib/grape-swagger.rb +2 -2
- data/lib/grape-swagger/doc_methods.rb +65 -62
- data/lib/grape-swagger/doc_methods/build_model_definition.rb +53 -2
- data/lib/grape-swagger/doc_methods/data_type.rb +6 -6
- data/lib/grape-swagger/doc_methods/format_data.rb +2 -2
- data/lib/grape-swagger/doc_methods/operation_id.rb +2 -2
- data/lib/grape-swagger/doc_methods/parse_params.rb +19 -4
- data/lib/grape-swagger/endpoint.rb +37 -26
- data/lib/grape-swagger/endpoint/params_parser.rb +12 -5
- data/lib/grape-swagger/rake/oapi_tasks.rb +12 -2
- data/lib/grape-swagger/version.rb +1 -1
- data/spec/issues/427_entity_as_string_spec.rb +1 -1
- data/spec/issues/430_entity_definitions_spec.rb +7 -5
- data/spec/issues/784_extensions_on_params_spec.rb +38 -0
- data/spec/lib/data_type_spec.rb +14 -2
- data/spec/lib/endpoint/params_parser_spec.rb +2 -1
- data/spec/lib/endpoint_spec.rb +1 -1
- data/spec/lib/move_params_spec.rb +2 -2
- data/spec/lib/oapi_tasks_spec.rb +15 -5
- data/spec/support/empty_model_parser.rb +1 -2
- data/spec/support/mock_parser.rb +1 -2
- data/spec/support/model_parsers/entity_parser.rb +9 -9
- data/spec/support/model_parsers/mock_parser.rb +8 -8
- data/spec/support/model_parsers/representable_parser.rb +9 -9
- data/spec/swagger_v2/api_swagger_v2_hide_param_spec.rb +14 -3
- data/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb +2 -2
- data/spec/swagger_v2/api_swagger_v2_response_with_models_spec.rb +53 -0
- data/spec/swagger_v2/boolean_params_spec.rb +1 -1
- data/spec/swagger_v2/inheritance_and_discriminator_spec.rb +56 -0
- data/spec/swagger_v2/reference_entity_spec.rb +74 -29
- data/spec/swagger_v2/security_requirement_spec.rb +2 -2
- metadata +17 -31
data/UPGRADING.md
CHANGED
@@ -1,5 +1,39 @@
|
|
1
1
|
## Upgrading Grape-swagger
|
2
2
|
|
3
|
+
### Upgrading to >= 1.3.0
|
4
|
+
|
5
|
+
- The model (entity) description no longer comes from the route description. It will have a default value: `<<EntityName>> model`.
|
6
|
+
|
7
|
+
### Upgrading to >= 1.2.0
|
8
|
+
|
9
|
+
- The entity_name class method is now called on parent classes for inherited entities. Now you can do this
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
module Some::Long::Module
|
13
|
+
class Base < Grape::Entity
|
14
|
+
# ... other shared logic
|
15
|
+
def self.entity_name
|
16
|
+
"V2::#{self.to_s.demodulize}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def MyEntity < Base
|
21
|
+
# ....
|
22
|
+
end
|
23
|
+
|
24
|
+
def OtherEntity < Base
|
25
|
+
# revert back to the default behavior by hiding the method
|
26
|
+
private_class_method :entity_name
|
27
|
+
end
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
- Full class name is modified to use `_` separator (e.g. `A_B_C` instead of `A::B::C`).
|
32
|
+
|
33
|
+
### Upgrading to >= 1.1.0
|
34
|
+
|
35
|
+
Full class name is used for referencing entity by default (e.g. `A::B::C` instead of just `C`). `Entity` and `Entities` suffixes and prefixes are omitted (e.g. if entity name is `Entities::SomeScope::MyFavourite::Entity` only `SomeScope::MyFavourite` will be used).
|
36
|
+
|
3
37
|
### Upgrading to >= 0.26.1
|
4
38
|
|
5
39
|
The format can now be specified,
|
data/grape-swagger.gemspec
CHANGED
@@ -14,8 +14,7 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.license = 'MIT'
|
15
15
|
|
16
16
|
s.required_ruby_version = '>= 2.4'
|
17
|
-
s.add_runtime_dependency 'grape', '
|
18
|
-
s.add_runtime_dependency 'rack', '2.0.8'
|
17
|
+
s.add_runtime_dependency 'grape', '~> 1.3'
|
19
18
|
|
20
19
|
s.files = `git ls-files`.split("\n")
|
21
20
|
s.test_files = `git ls-files -- {test,spec}/*`.split("\n")
|
data/lib/grape-swagger.rb
CHANGED
@@ -107,8 +107,8 @@ module SwaggerRouting
|
|
107
107
|
end
|
108
108
|
|
109
109
|
module SwaggerDocumentationAdder
|
110
|
-
attr_accessor :combined_namespaces, :combined_namespace_identifiers
|
111
|
-
|
110
|
+
attr_accessor :combined_namespaces, :combined_namespace_identifiers, :combined_routes, :combined_namespace_routes
|
111
|
+
|
112
112
|
include SwaggerRouting
|
113
113
|
|
114
114
|
def add_swagger_documentation(options = {})
|
@@ -17,6 +17,61 @@ require 'grape-swagger/doc_methods/version'
|
|
17
17
|
|
18
18
|
module GrapeSwagger
|
19
19
|
module DocMethods
|
20
|
+
DEFAULTS =
|
21
|
+
{
|
22
|
+
info: {},
|
23
|
+
models: [],
|
24
|
+
doc_version: '0.0.1',
|
25
|
+
target_class: nil,
|
26
|
+
mount_path: '/swagger_doc',
|
27
|
+
host: nil,
|
28
|
+
base_path: nil,
|
29
|
+
add_base_path: false,
|
30
|
+
add_version: true,
|
31
|
+
add_root: false,
|
32
|
+
hide_documentation_path: true,
|
33
|
+
format: :json,
|
34
|
+
authorizations: nil,
|
35
|
+
security_definitions: nil,
|
36
|
+
security: nil,
|
37
|
+
api_documentation: { desc: 'Swagger compatible API description' },
|
38
|
+
specific_api_documentation: { desc: 'Swagger compatible API description for specific API' },
|
39
|
+
endpoint_auth_wrapper: nil,
|
40
|
+
swagger_endpoint_guard: nil,
|
41
|
+
token_owner: nil
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
FORMATTER_METHOD = %i[format default_format default_error_formatter].freeze
|
45
|
+
|
46
|
+
def self.output_path_definitions(combi_routes, endpoint, target_class, options)
|
47
|
+
output = endpoint.swagger_object(
|
48
|
+
target_class,
|
49
|
+
endpoint.request,
|
50
|
+
options
|
51
|
+
)
|
52
|
+
|
53
|
+
paths, definitions = endpoint.path_and_definition_objects(combi_routes, options)
|
54
|
+
tags = tags_from(paths, options)
|
55
|
+
|
56
|
+
output[:tags] = tags unless tags.empty? || paths.blank?
|
57
|
+
output[:paths] = paths unless paths.blank?
|
58
|
+
output[:definitions] = definitions unless definitions.blank?
|
59
|
+
|
60
|
+
output
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.tags_from(paths, options)
|
64
|
+
tags = GrapeSwagger::DocMethods::TagNameDescription.build(paths)
|
65
|
+
|
66
|
+
if options[:tags]
|
67
|
+
names = options[:tags].map { |t| t[:name] }
|
68
|
+
tags.reject! { |t| names.include?(t[:name]) }
|
69
|
+
tags += options[:tags]
|
70
|
+
end
|
71
|
+
|
72
|
+
tags
|
73
|
+
end
|
74
|
+
|
20
75
|
def hide_documentation_path
|
21
76
|
@@hide_documentation_path
|
22
77
|
end
|
@@ -26,54 +81,32 @@ module GrapeSwagger
|
|
26
81
|
end
|
27
82
|
|
28
83
|
def setup(options)
|
29
|
-
options =
|
84
|
+
options = DEFAULTS.merge(options)
|
30
85
|
|
31
86
|
# options could be set on #add_swagger_documentation call,
|
32
87
|
# for available options see #defaults
|
33
88
|
target_class = options[:target_class]
|
34
89
|
guard = options[:swagger_endpoint_guard]
|
35
|
-
formatter = options[:format]
|
36
90
|
api_doc = options[:api_documentation].dup
|
37
91
|
specific_api_doc = options[:specific_api_documentation].dup
|
38
92
|
|
39
93
|
class_variables_from(options)
|
40
94
|
|
41
|
-
|
42
|
-
%i[format default_format default_error_formatter].each do |method|
|
43
|
-
send(method, formatter)
|
44
|
-
end
|
45
|
-
end
|
95
|
+
setup_formatter(options[:format])
|
46
96
|
|
47
97
|
desc api_doc.delete(:desc), api_doc
|
48
98
|
|
49
|
-
output_path_definitions = proc do |combi_routes, endpoint|
|
50
|
-
output = endpoint.swagger_object(
|
51
|
-
target_class,
|
52
|
-
endpoint.request,
|
53
|
-
options
|
54
|
-
)
|
55
|
-
|
56
|
-
paths, definitions = endpoint.path_and_definition_objects(combi_routes, options)
|
57
|
-
tags = tags_from(paths, options)
|
58
|
-
|
59
|
-
output[:tags] = tags unless tags.empty? || paths.blank?
|
60
|
-
output[:paths] = paths unless paths.blank?
|
61
|
-
output[:definitions] = definitions unless definitions.blank?
|
62
|
-
|
63
|
-
output
|
64
|
-
end
|
65
|
-
|
66
99
|
instance_eval(guard) unless guard.nil?
|
67
100
|
|
68
101
|
get mount_path do
|
69
102
|
header['Access-Control-Allow-Origin'] = '*'
|
70
103
|
header['Access-Control-Request-Method'] = '*'
|
71
104
|
|
72
|
-
|
105
|
+
GrapeSwagger::DocMethods
|
106
|
+
.output_path_definitions(target_class.combined_namespace_routes, self, target_class, options)
|
73
107
|
end
|
74
108
|
|
75
|
-
desc specific_api_doc.delete(:desc), { params:
|
76
|
-
specific_api_doc.delete(:params) || {} }.merge(specific_api_doc)
|
109
|
+
desc specific_api_doc.delete(:desc), { params: specific_api_doc.delete(:params) || {}, **specific_api_doc }
|
77
110
|
|
78
111
|
params do
|
79
112
|
requires :name, type: String, desc: 'Resource name of mounted API'
|
@@ -88,51 +121,21 @@ module GrapeSwagger
|
|
88
121
|
combined_routes = target_class.combined_namespace_routes[params[:name]]
|
89
122
|
error!({ error: 'named resource not exist' }, 400) if combined_routes.nil?
|
90
123
|
|
91
|
-
|
124
|
+
GrapeSwagger::DocMethods
|
125
|
+
.output_path_definitions({ params[:name] => combined_routes }, self, target_class, options)
|
92
126
|
end
|
93
127
|
end
|
94
128
|
|
95
|
-
def defaults
|
96
|
-
{
|
97
|
-
info: {},
|
98
|
-
models: [],
|
99
|
-
doc_version: '0.0.1',
|
100
|
-
target_class: nil,
|
101
|
-
mount_path: '/swagger_doc',
|
102
|
-
host: nil,
|
103
|
-
base_path: nil,
|
104
|
-
add_base_path: false,
|
105
|
-
add_version: true,
|
106
|
-
add_root: false,
|
107
|
-
hide_documentation_path: true,
|
108
|
-
format: :json,
|
109
|
-
authorizations: nil,
|
110
|
-
security_definitions: nil,
|
111
|
-
security: nil,
|
112
|
-
api_documentation: { desc: 'Swagger compatible API description' },
|
113
|
-
specific_api_documentation: { desc: 'Swagger compatible API description for specific API' },
|
114
|
-
endpoint_auth_wrapper: nil,
|
115
|
-
swagger_endpoint_guard: nil,
|
116
|
-
token_owner: nil
|
117
|
-
}
|
118
|
-
end
|
119
|
-
|
120
129
|
def class_variables_from(options)
|
121
130
|
@@mount_path = options[:mount_path]
|
122
131
|
@@class_name = options[:class_name] || options[:mount_path].delete('/')
|
123
132
|
@@hide_documentation_path = options[:hide_documentation_path]
|
124
133
|
end
|
125
134
|
|
126
|
-
def
|
127
|
-
|
135
|
+
def setup_formatter(formatter)
|
136
|
+
return unless formatter
|
128
137
|
|
129
|
-
|
130
|
-
names = options[:tags].map { |t| t[:name] }
|
131
|
-
tags.reject! { |t| names.include?(t[:name]) }
|
132
|
-
tags += options[:tags]
|
133
|
-
end
|
134
|
-
|
135
|
-
tags
|
138
|
+
FORMATTER_METHOD.each { |method| send(method, formatter) }
|
136
139
|
end
|
137
140
|
end
|
138
141
|
end
|
@@ -4,8 +4,8 @@ module GrapeSwagger
|
|
4
4
|
module DocMethods
|
5
5
|
class BuildModelDefinition
|
6
6
|
class << self
|
7
|
-
def build(model, properties, required)
|
8
|
-
definition = { type: 'object', properties: properties }
|
7
|
+
def build(model, properties, required, other_def_properties = {})
|
8
|
+
definition = { type: 'object', properties: properties }.merge(other_def_properties)
|
9
9
|
|
10
10
|
if required.nil?
|
11
11
|
required_attrs = required_attributes(model)
|
@@ -17,6 +17,57 @@ module GrapeSwagger
|
|
17
17
|
definition
|
18
18
|
end
|
19
19
|
|
20
|
+
def parse_params_from_model(parsed_response, model, model_name)
|
21
|
+
if parsed_response.is_a?(Hash) && parsed_response.keys.first == :allOf
|
22
|
+
refs_or_models = parsed_response[:allOf]
|
23
|
+
parsed = parse_refs_and_models(refs_or_models, model)
|
24
|
+
|
25
|
+
{
|
26
|
+
allOf: parsed
|
27
|
+
}
|
28
|
+
else
|
29
|
+
properties, required = parsed_response
|
30
|
+
unless properties&.any?
|
31
|
+
raise GrapeSwagger::Errors::SwaggerSpec,
|
32
|
+
"Empty model #{model_name}, swagger 2.0 doesn't support empty definitions."
|
33
|
+
end
|
34
|
+
properties, other_def_properties = parse_properties(properties)
|
35
|
+
|
36
|
+
build(
|
37
|
+
model, properties, required, other_def_properties
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_properties(properties)
|
43
|
+
other_properties = {}
|
44
|
+
|
45
|
+
discriminator_key, discriminator_value =
|
46
|
+
properties.find do |_key, value|
|
47
|
+
value[:documentation].try(:[], :is_discriminator)
|
48
|
+
end
|
49
|
+
|
50
|
+
if discriminator_key
|
51
|
+
discriminator_value.delete(:documentation)
|
52
|
+
properties[discriminator_key] = discriminator_value
|
53
|
+
|
54
|
+
other_properties[:discriminator] = discriminator_key
|
55
|
+
end
|
56
|
+
|
57
|
+
[properties, other_properties]
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_refs_and_models(refs_or_models, model)
|
61
|
+
refs_or_models.map do |ref_or_models|
|
62
|
+
if ref_or_models.is_a?(Hash) && ref_or_models.keys.first == '$ref'
|
63
|
+
ref_or_models
|
64
|
+
else
|
65
|
+
properties, required = ref_or_models
|
66
|
+
GrapeSwagger::DocMethods::BuildModelDefinition.build(model, properties, required)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
20
71
|
private
|
21
72
|
|
22
73
|
def required_attributes(model)
|
@@ -16,7 +16,7 @@ module GrapeSwagger
|
|
16
16
|
'object'
|
17
17
|
when 'Rack::Multipart::UploadedFile', 'File'
|
18
18
|
'file'
|
19
|
-
when '
|
19
|
+
when 'Grape::API::Boolean'
|
20
20
|
'boolean'
|
21
21
|
when 'BigDecimal'
|
22
22
|
'double'
|
@@ -48,14 +48,14 @@ module GrapeSwagger
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def parse_entity_name(model)
|
51
|
-
if model.
|
51
|
+
if model.respond_to?(:entity_name)
|
52
52
|
model.entity_name
|
53
53
|
elsif model.to_s.end_with?('::Entity', '::Entities')
|
54
|
-
model.to_s.split('::')[
|
55
|
-
elsif model.
|
56
|
-
model.
|
54
|
+
model.to_s.split('::')[0..-2].join('_')
|
55
|
+
elsif model.to_s.start_with?('Entity::', 'Entities::', 'Representable::')
|
56
|
+
model.to_s.split('::')[1..-1].join('_')
|
57
57
|
else
|
58
|
-
model.to_s.split('::').
|
58
|
+
model.to_s.split('::').join('_')
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -7,7 +7,7 @@ module GrapeSwagger
|
|
7
7
|
def to_format(parameters)
|
8
8
|
parameters.reject { |parameter| parameter[:in] == 'body' }.each do |b|
|
9
9
|
related_parameters = parameters.select do |p|
|
10
|
-
p[:name] != b[:name] && p[:name].to_s.include?(b[:name].to_s.gsub(/\[\]\z/, '')
|
10
|
+
p[:name] != b[:name] && p[:name].to_s.include?("#{b[:name].to_s.gsub(/\[\]\z/, '')}[")
|
11
11
|
end
|
12
12
|
parameters.reject! { |p| p[:name] == b[:name] } if move_down(b, related_parameters)
|
13
13
|
end
|
@@ -30,7 +30,7 @@ module GrapeSwagger
|
|
30
30
|
|
31
31
|
def add_braces(parameter, related_parameters)
|
32
32
|
param_name = parameter[:name].gsub(/\A(.*)\[\]\z/, '\1')
|
33
|
-
related_parameters.each { |p| p[:name] = p[:name].gsub(param_name, param_name
|
33
|
+
related_parameters.each { |p| p[:name] = p[:name].gsub(param_name, "#{param_name}[]") }
|
34
34
|
end
|
35
35
|
|
36
36
|
def add_array(parameter, related_parameters)
|
@@ -16,8 +16,8 @@ module GrapeSwagger
|
|
16
16
|
|
17
17
|
def manipulate(path)
|
18
18
|
operation = path.split('/').map(&:capitalize).join
|
19
|
-
operation.gsub!(
|
20
|
-
operation.gsub!(
|
19
|
+
operation.gsub!(/-(\w)/, &:upcase).delete!('-') if operation[/-(\w)/]
|
20
|
+
operation.gsub!(/_(\w)/, &:upcase).delete!('_') if operation.include?('_')
|
21
21
|
operation.gsub!(/\.(\w)/, &:upcase).delete!('.') if operation[/\.(\w)/]
|
22
22
|
if path.include?('{')
|
23
23
|
operation.gsub!(/\{(\w)/, &:upcase)
|
@@ -26,6 +26,7 @@ module GrapeSwagger
|
|
26
26
|
document_range_values(settings) unless value_type[:is_array]
|
27
27
|
document_required(settings)
|
28
28
|
document_additional_properties(settings)
|
29
|
+
document_add_extensions(settings)
|
29
30
|
|
30
31
|
@parsed_param
|
31
32
|
end
|
@@ -62,6 +63,10 @@ module GrapeSwagger
|
|
62
63
|
@parsed_param[:format] = settings[:format] if settings[:format].present?
|
63
64
|
end
|
64
65
|
|
66
|
+
def document_add_extensions(settings)
|
67
|
+
GrapeSwagger::DocMethods::Extensions.add_extensions_to_root(settings, @parsed_param)
|
68
|
+
end
|
69
|
+
|
65
70
|
def document_array_param(value_type, definitions)
|
66
71
|
if value_type[:documentation].present?
|
67
72
|
param_type = value_type[:documentation][:param_type]
|
@@ -72,6 +77,19 @@ module GrapeSwagger
|
|
72
77
|
|
73
78
|
param_type ||= value_type[:param_type]
|
74
79
|
|
80
|
+
array_items = parse_array_item(
|
81
|
+
definitions,
|
82
|
+
type,
|
83
|
+
value_type
|
84
|
+
)
|
85
|
+
|
86
|
+
@parsed_param[:in] = param_type || 'formData'
|
87
|
+
@parsed_param[:items] = array_items
|
88
|
+
@parsed_param[:type] = 'array'
|
89
|
+
@parsed_param[:collectionFormat] = collection_format if DataType.collections.include?(collection_format)
|
90
|
+
end
|
91
|
+
|
92
|
+
def parse_array_item(definitions, type, value_type)
|
75
93
|
array_items = {}
|
76
94
|
if definitions[value_type[:data_type]]
|
77
95
|
array_items['$ref'] = "#/definitions/#{@parsed_param[:type]}"
|
@@ -86,10 +104,7 @@ module GrapeSwagger
|
|
86
104
|
|
87
105
|
array_items[:default] = value_type[:default] if value_type[:default].present?
|
88
106
|
|
89
|
-
|
90
|
-
@parsed_param[:items] = array_items
|
91
|
-
@parsed_param[:type] = 'array'
|
92
|
-
@parsed_param[:collectionFormat] = collection_format if DataType.collections.include?(collection_format)
|
107
|
+
array_items
|
93
108
|
end
|
94
109
|
|
95
110
|
def document_additional_properties(settings)
|
@@ -11,7 +11,7 @@ module Grape
|
|
11
11
|
|
12
12
|
if content_types.empty?
|
13
13
|
formats = [target_class.format, target_class.default_format].compact.uniq
|
14
|
-
formats = Grape::Formatter.formatters({}).keys if formats.empty?
|
14
|
+
formats = Grape::Formatter.formatters(**{}).keys if formats.empty?
|
15
15
|
content_types = Grape::ContentTypes::CONTENT_TYPES.select do |content_type, _mime_type|
|
16
16
|
formats.include? content_type
|
17
17
|
end.values
|
@@ -78,11 +78,11 @@ module Grape
|
|
78
78
|
def path_and_definition_objects(namespace_routes, options)
|
79
79
|
@paths = {}
|
80
80
|
@definitions = {}
|
81
|
+
add_definitions_from options[:models]
|
81
82
|
namespace_routes.each_value do |routes|
|
82
83
|
path_item(routes, options)
|
83
84
|
end
|
84
85
|
|
85
|
-
add_definitions_from options[:models]
|
86
86
|
[@paths, @definitions]
|
87
87
|
end
|
88
88
|
|
@@ -175,15 +175,18 @@ module Grape
|
|
175
175
|
end
|
176
176
|
|
177
177
|
def params_object(route, options, path)
|
178
|
-
parameters =
|
178
|
+
parameters = build_request_params(route, options).each_with_object([]) do |(param, value), memo|
|
179
|
+
next if hidden_parameter?(value)
|
180
|
+
|
179
181
|
value = { required: false }.merge(value) if value.is_a?(Hash)
|
180
182
|
_, value = default_type([[param, value]]).first if value == ''
|
183
|
+
|
181
184
|
if value.dig(:documentation, :type)
|
182
185
|
expose_params(value[:documentation][:type])
|
183
186
|
elsif value[:type]
|
184
187
|
expose_params(value[:type])
|
185
188
|
end
|
186
|
-
GrapeSwagger::DocMethods::ParseParams.call(param, value, path, route, @definitions)
|
189
|
+
memo << GrapeSwagger::DocMethods::ParseParams.call(param, value, path, route, @definitions)
|
187
190
|
end
|
188
191
|
|
189
192
|
if GrapeSwagger::DocMethods::MoveParams.can_be_moved?(route.request_method, parameters)
|
@@ -196,10 +199,7 @@ module Grape
|
|
196
199
|
end
|
197
200
|
|
198
201
|
def response_object(route, options)
|
199
|
-
codes
|
200
|
-
codes.map! { |x| x.is_a?(Array) ? { code: x[0], message: x[1], model: x[2], examples: x[3], headers: x[4] } : x }
|
201
|
-
|
202
|
-
codes.each_with_object({}) do |value, memo|
|
202
|
+
codes(route).each_with_object({}) do |value, memo|
|
203
203
|
value[:message] ||= ''
|
204
204
|
memo[value[:code]] = { description: value[:message] }
|
205
205
|
|
@@ -207,24 +207,31 @@ module Grape
|
|
207
207
|
|
208
208
|
next build_file_response(memo[value[:code]]) if file_response?(value[:model])
|
209
209
|
|
210
|
-
response_model = @item
|
211
|
-
response_model = expose_params_from_model(value[:model]) if value[:model]
|
212
|
-
|
213
210
|
if memo.key?(200) && route.request_method == 'DELETE' && value[:model].nil?
|
214
211
|
memo[204] = memo.delete(200)
|
215
212
|
value[:code] = 204
|
213
|
+
next
|
216
214
|
end
|
217
215
|
|
218
|
-
|
219
|
-
next
|
216
|
+
# Explicitly request no model with { model: '' }
|
217
|
+
next if value[:model] == ''
|
220
218
|
|
221
|
-
|
219
|
+
response_model = value[:model] ? expose_params_from_model(value[:model]) : @item
|
220
|
+
next unless @definitions[response_model]
|
221
|
+
next if response_model.start_with?('Swagger_doc')
|
222
222
|
|
223
|
+
@definitions[response_model][:description] ||= "#{response_model} model"
|
223
224
|
memo[value[:code]][:schema] = build_reference(route, value, response_model, options)
|
224
225
|
memo[value[:code]][:examples] = value[:examples] if value[:examples]
|
225
226
|
end
|
226
227
|
end
|
227
228
|
|
229
|
+
def codes(route)
|
230
|
+
http_codes_from_route(route).map do |x|
|
231
|
+
x.is_a?(Array) ? { code: x[0], message: x[1], model: x[2], examples: x[3], headers: x[4] } : x
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
228
235
|
def success_code?(code)
|
229
236
|
status = code.is_a?(Array) ? code.first : code[:code]
|
230
237
|
status.between?(200, 299)
|
@@ -250,7 +257,7 @@ module Grape
|
|
250
257
|
|
251
258
|
def tag_object(route, path)
|
252
259
|
version = GrapeSwagger::DocMethods::Version.get(route)
|
253
|
-
version =
|
260
|
+
version = Array(version)
|
254
261
|
prefix = route.prefix.to_s.split('/').reject(&:empty?)
|
255
262
|
Array(
|
256
263
|
path.split('{')[0].split('/').reject(&:empty?).delete_if do |i|
|
@@ -293,16 +300,13 @@ module Grape
|
|
293
300
|
memo['schema'] = { type: 'file' }
|
294
301
|
end
|
295
302
|
|
296
|
-
def
|
297
|
-
declared_params = route.settings[:declared_params] if route.settings[:declared_params].present?
|
303
|
+
def build_request_params(route, settings)
|
298
304
|
required = merge_params(route)
|
299
305
|
required = GrapeSwagger::DocMethods::Headers.parse(route) + required unless route.headers.nil?
|
300
306
|
|
301
307
|
default_type(required)
|
302
308
|
|
303
|
-
request_params =
|
304
|
-
GrapeSwagger::Endpoint::ParamsParser.parse_request_params(required, settings)
|
305
|
-
end || {}
|
309
|
+
request_params = GrapeSwagger::Endpoint::ParamsParser.parse_request_params(required, settings, self)
|
306
310
|
|
307
311
|
request_params.empty? ? required : request_params
|
308
312
|
end
|
@@ -340,13 +344,10 @@ module Grape
|
|
340
344
|
parser = GrapeSwagger.model_parsers.find(model)
|
341
345
|
raise GrapeSwagger::Errors::UnregisteredParser, "No parser registered for #{model_name}." unless parser
|
342
346
|
|
343
|
-
|
344
|
-
unless properties&.any?
|
345
|
-
raise GrapeSwagger::Errors::SwaggerSpec,
|
346
|
-
"Empty model #{model_name}, swagger 2.0 doesn't support empty definitions."
|
347
|
-
end
|
347
|
+
parsed_response = parser.new(model, self).call
|
348
348
|
|
349
|
-
@definitions[model_name] =
|
349
|
+
@definitions[model_name] =
|
350
|
+
GrapeSwagger::DocMethods::BuildModelDefinition.parse_params_from_model(parsed_response, model, model_name)
|
350
351
|
|
351
352
|
model_name
|
352
353
|
end
|
@@ -363,6 +364,16 @@ module Grape
|
|
363
364
|
options[:token_owner] ? route_hidden.call(send(options[:token_owner].to_sym)) : route_hidden.call
|
364
365
|
end
|
365
366
|
|
367
|
+
def hidden_parameter?(value)
|
368
|
+
return false if value[:required]
|
369
|
+
|
370
|
+
if value.dig(:documentation, :hidden).is_a?(Proc)
|
371
|
+
value.dig(:documentation, :hidden).call
|
372
|
+
else
|
373
|
+
value.dig(:documentation, :hidden)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
366
377
|
def success_code_from_entity(route, entity)
|
367
378
|
default_code = GrapeSwagger::DocMethods::StatusCodes.get[route.request_method.downcase.to_sym]
|
368
379
|
if entity.is_a?(Hash)
|