gitlab-grape-openapi 0.2.3 → 0.3.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/lib/gitlab/grape_openapi/converters/entity_converter.rb +41 -4
- data/lib/gitlab/grape_openapi/converters/operation_converter.rb +2 -9
- data/lib/gitlab/grape_openapi/grape_compat.rb +50 -0
- data/lib/gitlab/grape_openapi/models/request_body/parameter_schema.rb +1 -6
- data/lib/gitlab/grape_openapi/models/schema.rb +6 -1
- data/lib/gitlab/grape_openapi/version.rb +1 -1
- data/lib/gitlab-grape-openapi.rb +1 -0
- metadata +13 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 79aec4f1d4657df18a7ccbcf6b689c9f00f8f0b5c940d508da34b05112aa8432
|
|
4
|
+
data.tar.gz: 275e4524ae0d61929af41ca0540ff080f49790f0a2cbb1308f4a0e6d6b79f75f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd0dfaa149fb09c6a61bd2b8c9256d506e6bc62da716faed13e9b0c2f48932efed53b69315c330d1f91f8bf550bb5728fc284865748966b39f15b4a7d7598c67
|
|
7
|
+
data.tar.gz: c937af8a3e5f1a4f80ae412e7d444f1b11c7d30268b5c64dd9441c3e2b6125db1b325387effa1ec917821211ee12ca7e140dd1f9e659bcab039c86d99c3e3db4
|
|
@@ -54,9 +54,28 @@ module Gitlab
|
|
|
54
54
|
Models::Schema.new.tap do |schema|
|
|
55
55
|
schema.type = OBJECT_TYPE
|
|
56
56
|
schema.properties = build_exposures_properties(root_exposures)
|
|
57
|
+
|
|
58
|
+
required = required_exposure_keys(root_exposures)
|
|
59
|
+
schema.required = required if required.any?
|
|
57
60
|
end
|
|
58
61
|
end
|
|
59
62
|
|
|
63
|
+
def required_exposure_keys(exposures)
|
|
64
|
+
exposures.flat_map do |exposure|
|
|
65
|
+
if inlineable_merge_exposure?(exposure)
|
|
66
|
+
# Merged entity properties become the parent's, so their
|
|
67
|
+
# `required` entries do too.
|
|
68
|
+
build_or_fetch_nested_schema(nested_entity_class(exposure))&.required || []
|
|
69
|
+
elsif block_exposure?(exposure) && exposure.for_merge
|
|
70
|
+
required_exposure_keys(exposure.nested_exposures)
|
|
71
|
+
elsif exposure_documentation(exposure)[:required]
|
|
72
|
+
[exposure.key.to_s]
|
|
73
|
+
else
|
|
74
|
+
[]
|
|
75
|
+
end
|
|
76
|
+
end.uniq
|
|
77
|
+
end
|
|
78
|
+
|
|
60
79
|
def build_exposures_properties(exposures)
|
|
61
80
|
exposures.each_with_object({}) do |exposure, properties|
|
|
62
81
|
if inlineable_merge_exposure?(exposure)
|
|
@@ -95,6 +114,9 @@ module Gitlab
|
|
|
95
114
|
object_schema = { type: OBJECT_TYPE }
|
|
96
115
|
object_schema[:properties] = nested_properties if nested_properties.any?
|
|
97
116
|
|
|
117
|
+
nested_required = required_exposure_keys(exposure.nested_exposures)
|
|
118
|
+
object_schema[:required] = nested_required if nested_required.any?
|
|
119
|
+
|
|
98
120
|
if documentation[:is_array]
|
|
99
121
|
{ type: ARRAY_TYPE, description: documentation[:desc], items: object_schema }.compact
|
|
100
122
|
else
|
|
@@ -169,11 +191,23 @@ module Gitlab
|
|
|
169
191
|
type: TypeResolver.resolve_type(actual_type) || DEFAULT_TYPE,
|
|
170
192
|
description: documentation[:desc],
|
|
171
193
|
format: TypeResolver.resolve_format(documentation[:format], actual_type),
|
|
194
|
+
enum: enum_values(documentation),
|
|
172
195
|
default: default_value,
|
|
173
196
|
example: documentation[:example]
|
|
174
197
|
}
|
|
175
198
|
end
|
|
176
199
|
|
|
200
|
+
# `values:` may also be a Proc or a Range (runtime validation
|
|
201
|
+
# constructs); only a literal Array translates to a fixed OpenAPI
|
|
202
|
+
# enum. Mirrors `ParameterConverter#build_enum_schema`. Symbols are
|
|
203
|
+
# stringified because the response contains strings, not symbols.
|
|
204
|
+
def enum_values(documentation)
|
|
205
|
+
values = documentation[:values]
|
|
206
|
+
return unless values.is_a?(Array) && values.any?
|
|
207
|
+
|
|
208
|
+
values.map { |value| value.is_a?(Symbol) ? value.to_s : value }
|
|
209
|
+
end
|
|
210
|
+
|
|
177
211
|
def build_type_schema(type, documentation)
|
|
178
212
|
schema = { type: TypeResolver.resolve_type(type) || DEFAULT_TYPE }
|
|
179
213
|
|
|
@@ -229,10 +263,13 @@ module Gitlab
|
|
|
229
263
|
def build_primitive_items(property, item_type)
|
|
230
264
|
items = { type: item_type }
|
|
231
265
|
|
|
232
|
-
# Move format to items if present
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
property[
|
|
266
|
+
# Move format and enum to items if present; they constrain each
|
|
267
|
+
# element, not the array itself
|
|
268
|
+
[:format, :enum].each do |key|
|
|
269
|
+
next unless property[key]
|
|
270
|
+
|
|
271
|
+
items[key] = property[key]
|
|
272
|
+
property[key] = nil
|
|
236
273
|
end
|
|
237
274
|
|
|
238
275
|
items
|
|
@@ -238,17 +238,10 @@ module Gitlab
|
|
|
238
238
|
# Looks something like:
|
|
239
239
|
# [{:attributes=>[:version_prefix],
|
|
240
240
|
# :options=>/^[\d+.]+/,
|
|
241
|
-
# :
|
|
242
|
-
# :params_scope=>#<Grape::Validations::ParamsScope:0x000000016dc35820
|
|
243
|
-
# :opts=>{:allow_blank=>nil, :fail_fast=>false},
|
|
241
|
+
# :opts=>{:fail_fast=>false},
|
|
244
242
|
# :validator_class=>Grape::Validations::Validators::RegexpValidator}]
|
|
245
243
|
def validations_for(attribute)
|
|
246
|
-
route
|
|
247
|
-
.app
|
|
248
|
-
.inheritable_setting
|
|
249
|
-
.namespace_stackable
|
|
250
|
-
.new_values[:validations]
|
|
251
|
-
&.select { |v| v[:attributes].include?(attribute) }
|
|
244
|
+
GrapeCompat.validations_for(route, attribute)
|
|
252
245
|
end
|
|
253
246
|
|
|
254
247
|
def extract_request_body
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module GrapeOpenapi
|
|
5
|
+
# Isolates the Grape internals this gem reads so version differences live in
|
|
6
|
+
# one place.
|
|
7
|
+
#
|
|
8
|
+
# Grape < 3.2 stores each declared validation as a Hash; Grape >= 3.2 stores
|
|
9
|
+
# a frozen validator instance instead (ruby-grape/grape#2657). Both shapes
|
|
10
|
+
# are normalized to the Hash the converters expect.
|
|
11
|
+
module GrapeCompat
|
|
12
|
+
class << self
|
|
13
|
+
# Declared validations for a single attribute, newest scope only.
|
|
14
|
+
#
|
|
15
|
+
# Reads `new_values` rather than `[]` or `route[:saved_validations]` on
|
|
16
|
+
# purpose: those also include validations inherited from parent scopes,
|
|
17
|
+
# which would change the generated output.
|
|
18
|
+
def validations_for(route, attribute)
|
|
19
|
+
validations = route.app.inheritable_setting.namespace_stackable.new_values[:validations]
|
|
20
|
+
return unless validations
|
|
21
|
+
|
|
22
|
+
validations.filter_map do |validation|
|
|
23
|
+
normalized = normalize(validation)
|
|
24
|
+
normalized if normalized && normalized[:attributes].include?(attribute)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def normalize(validation)
|
|
31
|
+
return validation if validation.is_a?(Hash)
|
|
32
|
+
|
|
33
|
+
# Grape 3.2's ContractScopeValidator declares no attributes, so it maps
|
|
34
|
+
# to no parameter.
|
|
35
|
+
return unless validation.respond_to?(:attrs)
|
|
36
|
+
|
|
37
|
+
{
|
|
38
|
+
attributes: validation.attrs,
|
|
39
|
+
validator_class: validation.class,
|
|
40
|
+
# Grape 3.2 exposes no public reader for the validator options, which
|
|
41
|
+
# carry regexp patterns and limits. Switch to the reader if one is
|
|
42
|
+
# added upstream.
|
|
43
|
+
options: validation.instance_variable_get(:@options),
|
|
44
|
+
opts: { fail_fast: validation.fail_fast? }
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -226,12 +226,7 @@ module Gitlab
|
|
|
226
226
|
end
|
|
227
227
|
|
|
228
228
|
def validations_for(attribute)
|
|
229
|
-
route
|
|
230
|
-
.app
|
|
231
|
-
.inheritable_setting
|
|
232
|
-
.namespace_stackable
|
|
233
|
-
.new_values[:validations]
|
|
234
|
-
&.select { |v| v[:attributes].include?(attribute) }
|
|
229
|
+
GrapeCompat.validations_for(route, attribute)
|
|
235
230
|
end
|
|
236
231
|
|
|
237
232
|
def apply_allow_blank(schema)
|
|
@@ -5,7 +5,7 @@ module Gitlab
|
|
|
5
5
|
module Models
|
|
6
6
|
# https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#schema-object
|
|
7
7
|
class Schema
|
|
8
|
-
attr_accessor :properties, :type
|
|
8
|
+
attr_accessor :properties, :required, :type
|
|
9
9
|
|
|
10
10
|
def initialize
|
|
11
11
|
@properties = {}
|
|
@@ -31,6 +31,7 @@ module Gitlab
|
|
|
31
31
|
{}.tap do |hash|
|
|
32
32
|
add_type(hash)
|
|
33
33
|
add_properties(hash)
|
|
34
|
+
add_required(hash)
|
|
34
35
|
end
|
|
35
36
|
end
|
|
36
37
|
|
|
@@ -44,6 +45,10 @@ module Gitlab
|
|
|
44
45
|
hash[:properties] = properties.transform_values(&:to_h)
|
|
45
46
|
end
|
|
46
47
|
|
|
48
|
+
def add_required(hash)
|
|
49
|
+
hash[:required] = required if required && !required.empty?
|
|
50
|
+
end
|
|
51
|
+
|
|
47
52
|
def description
|
|
48
53
|
@properties[:description]
|
|
49
54
|
end
|
data/lib/gitlab-grape-openapi.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "gitlab/grape_openapi/version"
|
|
4
|
+
require_relative "gitlab/grape_openapi/grape_compat"
|
|
4
5
|
require_relative "gitlab/grape_openapi/configuration"
|
|
5
6
|
require_relative "gitlab/grape_openapi/generator"
|
|
6
7
|
require_relative "gitlab/grape_openapi/schema_registry"
|
metadata
CHANGED
|
@@ -1,29 +1,35 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gitlab-grape-openapi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- group::api
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: grape
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.4'
|
|
20
|
+
- - "<"
|
|
18
21
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
22
|
+
version: '3.3'
|
|
20
23
|
type: :runtime
|
|
21
24
|
prerelease: false
|
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
26
|
requirements:
|
|
24
|
-
- - "
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '2.4'
|
|
30
|
+
- - "<"
|
|
25
31
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
32
|
+
version: '3.3'
|
|
27
33
|
- !ruby/object:Gem::Dependency
|
|
28
34
|
name: grape-entity
|
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -148,6 +154,7 @@ files:
|
|
|
148
154
|
- lib/gitlab/grape_openapi/converters/tag_converter.rb
|
|
149
155
|
- lib/gitlab/grape_openapi/converters/type_resolver.rb
|
|
150
156
|
- lib/gitlab/grape_openapi/generator.rb
|
|
157
|
+
- lib/gitlab/grape_openapi/grape_compat.rb
|
|
151
158
|
- lib/gitlab/grape_openapi/models/info.rb
|
|
152
159
|
- lib/gitlab/grape_openapi/models/operation.rb
|
|
153
160
|
- lib/gitlab/grape_openapi/models/parameter.rb
|