grape-swagger 2.0.2 → 2.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -1
- data/UPGRADING.md +9 -0
- data/lib/grape-swagger/doc_methods/data_type.rb +8 -0
- data/lib/grape-swagger/doc_methods/move_params.rb +4 -15
- data/lib/grape-swagger/doc_methods/parse_params.rb +11 -9
- data/lib/grape-swagger/endpoint.rb +3 -3
- data/lib/grape-swagger/rake/oapi_tasks.rb +5 -5
- data/lib/grape-swagger/version.rb +1 -1
- data/lib/grape-swagger.rb +34 -29
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fbf69e7e7bc7f3a836c574fe91df74abb10aab05c778cee716398d76afeace6
|
4
|
+
data.tar.gz: 5ab4bc60eafa3ad32959a040aed645943121912037a738278d88fb649390a0fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8bcb10791418aa79af266d503f7fd5130157bb7971d7acb094964981d9ee8635fe6bcf72e212b81f22a25f2032a002fba99b97a7d078d8d35a908f0117fae379
|
7
|
+
data.tar.gz: d7843b9aaf70d83a9d0de3dc7f075b8f3df2e4cedda4a1c519cbc4109dc9da1cb1de82c9966fcf6a0083ebbe22a89c13654fbd9fe9e1156af4103e8bc70a344e
|
data/CHANGELOG.md
CHANGED
@@ -9,6 +9,27 @@
|
|
9
9
|
* Your contribution here.
|
10
10
|
|
11
11
|
|
12
|
+
### 2.1.0 (May 14, 2024)
|
13
|
+
|
14
|
+
#### Features
|
15
|
+
|
16
|
+
* [#927](https://github.com/ruby-grape/grape-swagger/pull/927): Set default parameter location based on consumes - [@spaceraccoon](https://github.com/spaceraccoon)
|
17
|
+
* [#929](https://github.com/ruby-grape/grape-swagger/pull/929): Set query parameter for array of primitive types - [@spaceraccoon](https://github.com/spaceraccoon)
|
18
|
+
|
19
|
+
#### Fixes
|
20
|
+
|
21
|
+
* [#926](https://github.com/ruby-grape/grape-swagger/pull/926): Refactor route and namespace combination logic - [@numbata](https://github.com/numbata)
|
22
|
+
|
23
|
+
|
24
|
+
### 2.0.3 (April 26, 2024)
|
25
|
+
|
26
|
+
#### Fixes
|
27
|
+
|
28
|
+
* [#922](https://github.com/ruby-grape/grape-swagger/pull/922): Force request body to be an schema object - [@numbata](https://github.com/numbata)
|
29
|
+
* [#923](https://github.com/ruby-grape/grape-swagger/pull/923): Enabled schema definitions for body parameters in DELETE requests - [@numbata](https://github.com/numbata)
|
30
|
+
* [#924](https://github.com/ruby-grape/grape-swagger/pull/924): fix: Use mount_path to narrow down urls_for - [@chibicco](https://github.com/chibicco)
|
31
|
+
|
32
|
+
|
12
33
|
### 2.0.2 (Februar 2, 2024)
|
13
34
|
|
14
35
|
#### Fixes
|
@@ -72,7 +93,6 @@
|
|
72
93
|
* [#846](https://github.com/ruby-grape/grape-swagger/pull/846): Refactor oapi fetch task [@Vachman](https://github.com/Vachman)
|
73
94
|
* [#850](https://github.com/ruby-grape/grape-swagger/pull/850): Fix value of enum to be Array [@takahashim](https://github.com/takahashim)
|
74
95
|
|
75
|
-
|
76
96
|
### 1.4.3 (January 5, 2022)
|
77
97
|
|
78
98
|
#### Fixes
|
data/UPGRADING.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
## Upgrading Grape-swagger
|
2
2
|
|
3
|
+
### Upgrading to >= x.y.z
|
4
|
+
|
5
|
+
- Grape-swagger now documents array parameters within an object schema in Swagger. This aligns with grape's JSON structure requirements and ensures the documentation is correct.
|
6
|
+
- Previously, arrays were documented as standalone arrays, which could be incorrect based on grape's expectations.
|
7
|
+
- Check your API documentation and update your code or tests that use the old array format.
|
8
|
+
|
9
|
+
Attention: This update may require you to make changes to ensure your API integrations continue to work correctly.
|
10
|
+
For detailed reasons behind this update, refer to GitHub issue #666.
|
11
|
+
|
3
12
|
### Upgrading to >= 1.5.0
|
4
13
|
|
5
14
|
- The names generated for body parameter definitions and their references has changed. It'll now include the HTTP action as well as any path parameters.
|
@@ -75,6 +75,14 @@ module GrapeSwagger
|
|
75
75
|
PRIMITIVE_MAPPINGS.keys.map(&:downcase)
|
76
76
|
end
|
77
77
|
|
78
|
+
def query_array_primitive?(type)
|
79
|
+
query_array_primitives.include?(type.to_s.downcase)
|
80
|
+
end
|
81
|
+
|
82
|
+
def query_array_primitives
|
83
|
+
primitives << 'string'
|
84
|
+
end
|
85
|
+
|
78
86
|
def mapping(value)
|
79
87
|
PRIMITIVE_MAPPINGS[value] || 'string'
|
80
88
|
end
|
@@ -18,8 +18,6 @@ module GrapeSwagger
|
|
18
18
|
|
19
19
|
params_to_move = movable_params(params)
|
20
20
|
|
21
|
-
return (params + correct_array_param(params_to_move)) if should_correct_array?(params_to_move)
|
22
|
-
|
23
21
|
params << parent_definition_of_params(params_to_move, path, route)
|
24
22
|
|
25
23
|
params
|
@@ -27,21 +25,11 @@ module GrapeSwagger
|
|
27
25
|
|
28
26
|
private
|
29
27
|
|
30
|
-
def should_correct_array?(param)
|
31
|
-
param.length == 1 && param.first[:in] == 'body' && param.first[:type] == 'array'
|
32
|
-
end
|
33
|
-
|
34
|
-
def correct_array_param(param)
|
35
|
-
param.first[:schema] = { type: param.first.delete(:type), items: param.first.delete(:items) }
|
36
|
-
|
37
|
-
param
|
38
|
-
end
|
39
|
-
|
40
28
|
def parent_definition_of_params(params, path, route)
|
41
29
|
definition_name = OperationId.build(route, path)
|
42
|
-
|
30
|
+
# NOTE: Parent definition is always object
|
31
|
+
@definitions[definition_name] = object_type
|
43
32
|
definition = @definitions[definition_name]
|
44
|
-
|
45
33
|
move_params_to_new(definition, params)
|
46
34
|
|
47
35
|
definition[:description] = route.description if route.try(:description)
|
@@ -53,6 +41,7 @@ module GrapeSwagger
|
|
53
41
|
params, nested_params = params.partition { |x| !x[:name].to_s.include?('[') }
|
54
42
|
params.each do |param|
|
55
43
|
property = param[:name]
|
44
|
+
|
56
45
|
param_properties, param_required = build_properties([param])
|
57
46
|
add_properties_to_definition(definition, param_properties, param_required)
|
58
47
|
related_nested_params, nested_params = nested_params.partition { |x| x[:name].start_with?("#{property}[") }
|
@@ -197,7 +186,7 @@ module GrapeSwagger
|
|
197
186
|
end
|
198
187
|
|
199
188
|
def move_methods
|
200
|
-
[:post, :put, :patch, 'POST', 'PUT', 'PATCH']
|
189
|
+
[:delete, :post, :put, :patch, 'DELETE', 'POST', 'PUT', 'PATCH']
|
201
190
|
end
|
202
191
|
|
203
192
|
def includes_body_param?(params)
|
@@ -4,7 +4,7 @@ module GrapeSwagger
|
|
4
4
|
module DocMethods
|
5
5
|
class ParseParams
|
6
6
|
class << self
|
7
|
-
def call(param, settings, path, route, definitions)
|
7
|
+
def call(param, settings, path, route, definitions, consumes) # rubocop:disable Metrics/ParameterLists
|
8
8
|
method = route.request_method
|
9
9
|
additional_documentation = settings.fetch(:documentation, {})
|
10
10
|
settings.merge!(additional_documentation)
|
@@ -14,7 +14,7 @@ module GrapeSwagger
|
|
14
14
|
|
15
15
|
# required properties
|
16
16
|
@parsed_param = {
|
17
|
-
in: param_type(value_type),
|
17
|
+
in: param_type(value_type, consumes),
|
18
18
|
name: settings[:full_name] || param
|
19
19
|
}
|
20
20
|
|
@@ -70,21 +70,17 @@ module GrapeSwagger
|
|
70
70
|
|
71
71
|
def document_array_param(value_type, definitions)
|
72
72
|
if value_type[:documentation].present?
|
73
|
-
param_type = value_type[:documentation][:param_type]
|
74
73
|
doc_type = value_type[:documentation][:type]
|
75
74
|
type = DataType.mapping(doc_type) if doc_type && !DataType.request_primitive?(doc_type)
|
76
75
|
collection_format = value_type[:documentation][:collectionFormat]
|
77
76
|
end
|
78
77
|
|
79
|
-
param_type ||= value_type[:param_type]
|
80
|
-
|
81
78
|
array_items = parse_array_item(
|
82
79
|
definitions,
|
83
80
|
type,
|
84
81
|
value_type
|
85
82
|
)
|
86
83
|
|
87
|
-
@parsed_param[:in] = param_type || 'formData'
|
88
84
|
@parsed_param[:items] = array_items
|
89
85
|
@parsed_param[:type] = 'array'
|
90
86
|
@parsed_param[:collectionFormat] = collection_format if DataType.collections.include?(collection_format)
|
@@ -148,14 +144,20 @@ module GrapeSwagger
|
|
148
144
|
@parsed_param[:example] = example if example
|
149
145
|
end
|
150
146
|
|
151
|
-
def param_type(value_type)
|
147
|
+
def param_type(value_type, consumes)
|
152
148
|
param_type = value_type[:param_type] || value_type[:in]
|
153
|
-
if value_type[:path].include?("{#{value_type[:param_name]}}")
|
149
|
+
if !value_type[:is_array] && value_type[:path].include?("{#{value_type[:param_name]}}")
|
154
150
|
'path'
|
155
151
|
elsif param_type
|
156
152
|
param_type
|
157
153
|
elsif %w[POST PUT PATCH].include?(value_type[:method])
|
158
|
-
|
154
|
+
if consumes.include?('application/x-www-form-urlencoded') || consumes.include?('multipart/form-data')
|
155
|
+
'formData'
|
156
|
+
else
|
157
|
+
'body'
|
158
|
+
end
|
159
|
+
elsif value_type[:is_array] && !DataType.query_array_primitive?(value_type[:data_type])
|
160
|
+
'formData'
|
159
161
|
else
|
160
162
|
'query'
|
161
163
|
end
|
@@ -119,7 +119,7 @@ module Grape
|
|
119
119
|
method[:description] = description_object(route)
|
120
120
|
method[:produces] = produces_object(route, options[:produces] || options[:format])
|
121
121
|
method[:consumes] = consumes_object(route, options[:consumes] || options[:format])
|
122
|
-
method[:parameters] = params_object(route, options, path)
|
122
|
+
method[:parameters] = params_object(route, options, path, method[:consumes])
|
123
123
|
method[:security] = security_object(route)
|
124
124
|
method[:responses] = response_object(route, options)
|
125
125
|
method[:tags] = route.options.fetch(:tags, tag_object(route, path))
|
@@ -175,7 +175,7 @@ module Grape
|
|
175
175
|
GrapeSwagger::DocMethods::ProducesConsumes.call(route.settings.dig(:description, :consumes) || format)
|
176
176
|
end
|
177
177
|
|
178
|
-
def params_object(route, options, path)
|
178
|
+
def params_object(route, options, path, consumes)
|
179
179
|
parameters = build_request_params(route, options).each_with_object([]) do |(param, value), memo|
|
180
180
|
next if hidden_parameter?(value)
|
181
181
|
|
@@ -187,7 +187,7 @@ module Grape
|
|
187
187
|
elsif value[:type]
|
188
188
|
expose_params(value[:type])
|
189
189
|
end
|
190
|
-
memo << GrapeSwagger::DocMethods::ParseParams.call(param, value, path, route, @definitions)
|
190
|
+
memo << GrapeSwagger::DocMethods::ParseParams.call(param, value, path, route, @definitions, consumes)
|
191
191
|
end
|
192
192
|
|
193
193
|
if GrapeSwagger::DocMethods::MoveParams.can_be_moved?(route.request_method, parameters)
|
@@ -63,7 +63,7 @@ module GrapeSwagger
|
|
63
63
|
resource - if given only for that it would be generated (optional)'
|
64
64
|
task validate: :environment do
|
65
65
|
# :nocov:
|
66
|
-
ENV
|
66
|
+
ENV.store('store', 'true')
|
67
67
|
::Rake::Task['oapi:fetch'].invoke
|
68
68
|
exit if error?
|
69
69
|
|
@@ -95,7 +95,7 @@ module GrapeSwagger
|
|
95
95
|
def urls_for(api_class)
|
96
96
|
api_class.routes
|
97
97
|
.map(&:path)
|
98
|
-
.
|
98
|
+
.grep(/#{GrapeSwagger::DocMethods.class_variable_get(:@@mount_path)}/)
|
99
99
|
.reject { |e| e.include?(':name') }
|
100
100
|
.map { |e| format_path(e) }
|
101
101
|
.map { |e| [e, ENV.fetch('resource', nil)].join('/').chomp('/') }
|
@@ -108,7 +108,7 @@ module GrapeSwagger
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def save_to_file?
|
111
|
-
ENV
|
111
|
+
ENV.fetch('store', nil).present? && !error?
|
112
112
|
end
|
113
113
|
|
114
114
|
def error?
|
@@ -118,10 +118,10 @@ module GrapeSwagger
|
|
118
118
|
def file(url)
|
119
119
|
api_version = url.split('/').last
|
120
120
|
|
121
|
-
name = if ENV
|
121
|
+
name = if ENV.fetch('store', nil) == 'true' || ENV.fetch('store', nil).blank?
|
122
122
|
"swagger_doc_#{api_version}.json"
|
123
123
|
else
|
124
|
-
ENV
|
124
|
+
ENV.fetch('store').sub('.json', "_#{api_version}.json")
|
125
125
|
end
|
126
126
|
|
127
127
|
File.join(Dir.getwd, name)
|
data/lib/grape-swagger.rb
CHANGED
@@ -24,7 +24,7 @@ module SwaggerRouting
|
|
24
24
|
private
|
25
25
|
|
26
26
|
def combine_routes(app, doc_klass)
|
27
|
-
app.routes.
|
27
|
+
app.routes.each_with_object({}) do |route, combined_routes|
|
28
28
|
route_path = route.path
|
29
29
|
route_match = route_path.split(/^.*?#{route.prefix}/).last
|
30
30
|
next unless route_match
|
@@ -37,16 +37,16 @@ module SwaggerRouting
|
|
37
37
|
|
38
38
|
resource = route_match.captures.first
|
39
39
|
resource = '/' if resource.empty?
|
40
|
-
|
40
|
+
combined_routes[resource] ||= []
|
41
41
|
next if doc_klass.hide_documentation_path && route.path.match(/#{doc_klass.mount_path}($|\/|\(\.)/)
|
42
42
|
|
43
|
-
|
43
|
+
combined_routes[resource] << route
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
def determine_namespaced_routes(name, parent_route)
|
47
|
+
def determine_namespaced_routes(name, parent_route, routes)
|
48
48
|
if parent_route.nil?
|
49
|
-
|
49
|
+
routes.values.flatten
|
50
50
|
else
|
51
51
|
parent_route.reject do |route|
|
52
52
|
!route_path_start_with?(route, name) || !route_instance_variable_equals?(route, name)
|
@@ -54,14 +54,15 @@ module SwaggerRouting
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
def combine_namespace_routes(namespaces)
|
57
|
+
def combine_namespace_routes(namespaces, routes)
|
58
|
+
combined_namespace_routes = {}
|
58
59
|
# iterate over each single namespace
|
59
60
|
namespaces.each_key do |name, _|
|
60
61
|
# get the parent route for the namespace
|
61
62
|
parent_route_name = extract_parent_route(name)
|
62
|
-
parent_route =
|
63
|
+
parent_route = routes[parent_route_name]
|
63
64
|
# fetch all routes that are within the current namespace
|
64
|
-
namespace_routes = determine_namespaced_routes(name, parent_route)
|
65
|
+
namespace_routes = determine_namespaced_routes(name, parent_route, routes)
|
65
66
|
|
66
67
|
# default case when not explicitly specified or nested == true
|
67
68
|
standalone_namespaces = namespaces.reject do |_, ns|
|
@@ -76,12 +77,13 @@ module SwaggerRouting
|
|
76
77
|
# rubocop:disable Style/Next
|
77
78
|
if parent_standalone_namespaces.empty?
|
78
79
|
# default option, append namespace methods to parent route
|
79
|
-
|
80
|
-
|
81
|
-
@target_class.combined_namespace_routes[parent_route_name].push(*namespace_routes)
|
80
|
+
combined_namespace_routes[parent_route_name] ||= []
|
81
|
+
combined_namespace_routes[parent_route_name].push(*namespace_routes)
|
82
82
|
end
|
83
83
|
# rubocop:enable Style/Next
|
84
84
|
end
|
85
|
+
|
86
|
+
combined_namespace_routes
|
85
87
|
end
|
86
88
|
|
87
89
|
def extract_parent_route(name)
|
@@ -110,7 +112,7 @@ module SwaggerRouting
|
|
110
112
|
end
|
111
113
|
|
112
114
|
module SwaggerDocumentationAdder
|
113
|
-
attr_accessor :combined_namespaces, :
|
115
|
+
attr_accessor :combined_namespaces, :combined_routes, :combined_namespace_routes
|
114
116
|
|
115
117
|
include SwaggerRouting
|
116
118
|
|
@@ -127,20 +129,16 @@ module SwaggerDocumentationAdder
|
|
127
129
|
documentation_class.setup(options)
|
128
130
|
mount(documentation_class)
|
129
131
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
132
|
+
combined_routes = combine_routes(@target_class, documentation_class)
|
133
|
+
combined_namespaces = combine_namespaces(@target_class)
|
134
|
+
combined_namespace_routes = combine_namespace_routes(combined_namespaces, combined_routes)
|
135
|
+
exclusive_route_keys = combined_routes.keys - combined_namespaces.keys
|
136
|
+
@target_class.combined_namespace_routes = combined_namespace_routes.merge(
|
137
|
+
combined_routes.slice(*exclusive_route_keys)
|
138
|
+
)
|
139
|
+
@target_class.combined_routes = combined_routes
|
140
|
+
@target_class.combined_namespaces = combined_namespaces
|
135
141
|
|
136
|
-
@target_class.combined_namespace_routes = {}
|
137
|
-
@target_class.combined_namespace_identifiers = {}
|
138
|
-
combine_namespace_routes(@target_class.combined_namespaces)
|
139
|
-
|
140
|
-
exclusive_route_keys = @target_class.combined_routes.keys - @target_class.combined_namespaces.keys
|
141
|
-
exclusive_route_keys.each do |key|
|
142
|
-
@target_class.combined_namespace_routes[key] = @target_class.combined_routes[key]
|
143
|
-
end
|
144
142
|
documentation_class
|
145
143
|
end
|
146
144
|
|
@@ -151,17 +149,24 @@ module SwaggerDocumentationAdder
|
|
151
149
|
end
|
152
150
|
|
153
151
|
def combine_namespaces(app)
|
154
|
-
|
152
|
+
combined_namespaces = {}
|
153
|
+
endpoints = app.endpoints.clone
|
154
|
+
|
155
|
+
while endpoints.any?
|
156
|
+
endpoint = endpoints.shift
|
157
|
+
|
158
|
+
endpoints.push(*endpoint.options[:app].endpoints) if endpoint.options[:app]
|
155
159
|
ns = endpoint.namespace_stackable(:namespace).last
|
160
|
+
next unless ns
|
156
161
|
|
157
162
|
# use the full namespace here (not the latest level only)
|
158
163
|
# and strip leading slash
|
159
164
|
mount_path = (endpoint.namespace_stackable(:mount_path) || []).join('/')
|
160
165
|
full_namespace = (mount_path + endpoint.namespace).sub(/\/{2,}/, '/').sub(/^\//, '')
|
161
|
-
|
162
|
-
|
163
|
-
combine_namespaces(endpoint.options[:app]) if endpoint.options[:app]
|
166
|
+
combined_namespaces[full_namespace] = ns
|
164
167
|
end
|
168
|
+
|
169
|
+
combined_namespaces
|
165
170
|
end
|
166
171
|
|
167
172
|
def create_documentation_class
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grape-swagger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- LeFnord
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-05-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: grape
|
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
103
|
- !ruby/object:Gem::Version
|
104
104
|
version: '0'
|
105
105
|
requirements: []
|
106
|
-
rubygems_version: 3.5.
|
106
|
+
rubygems_version: 3.5.9
|
107
107
|
signing_key:
|
108
108
|
specification_version: 4
|
109
109
|
summary: Add auto generated documentation to your Grape API that can be displayed
|