grape-oas 1.5.0 → 1.6.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 +38 -0
- data/UPGRADING.md +38 -0
- data/lib/grape_oas/api_model_builder.rb +5 -4
- data/lib/grape_oas/api_model_builders/request.rb +8 -13
- data/lib/grape_oas/api_model_builders/request_params.rb +38 -41
- data/lib/grape_oas/api_model_builders/request_params_support/nested_params_builder.rb +0 -1
- data/lib/grape_oas/api_model_builders/request_params_support/param_location_resolver.rb +33 -27
- data/lib/grape_oas/api_model_builders/request_params_support/param_schema_builder.rb +7 -26
- data/lib/grape_oas/api_model_builders/request_params_support/schema_enhancer.rb +1 -1
- data/lib/grape_oas/api_model_builders/response.rb +5 -1
- data/lib/grape_oas/api_model_builders/response_parsers/base.rb +17 -0
- data/lib/grape_oas/api_model_builders/response_parsers/default_response_parser.rb +4 -7
- data/lib/grape_oas/api_model_builders/response_parsers/documentation_responses_parser.rb +5 -2
- data/lib/grape_oas/api_model_builders/response_parsers/http_codes_parser.rb +96 -28
- data/lib/grape_oas/constants.rb +14 -0
- data/lib/grape_oas/exporter/concerns/enum_normalizer.rb +35 -0
- data/lib/grape_oas/exporter/concerns/schema_indexer.rb +18 -1
- data/lib/grape_oas/exporter/oas2/parameter.rb +55 -30
- data/lib/grape_oas/exporter/oas2/schema.rb +9 -26
- data/lib/grape_oas/exporter/oas3/schema.rb +26 -39
- data/lib/grape_oas/introspectors/entity_introspector_support/exposure_processor.rb +40 -6
- data/lib/grape_oas/type_resolvers/array_resolver.rb +7 -14
- data/lib/grape_oas/version.rb +1 -1
- data/lib/grape_oas.rb +19 -0
- metadata +3 -2
|
@@ -44,10 +44,18 @@ module GrapeOAS
|
|
|
44
44
|
# @return [ApiModel::Schema] the built schema
|
|
45
45
|
def schema_for_exposure(exposure, doc)
|
|
46
46
|
opts = exposure_options(exposure)
|
|
47
|
-
|
|
47
|
+
nullable_type = Constants.nullable_type(doc[:types])
|
|
48
|
+
if opts[:using] && doc.key?(:types)
|
|
49
|
+
GrapeOAS.logger.warn("Ignoring types: because using: takes precedence")
|
|
50
|
+
elsif doc.key?(:types) && !nullable_type
|
|
51
|
+
GrapeOAS.logger.warn("Ignoring unsupported entity documentation types: #{doc[:types].inspect}")
|
|
52
|
+
end
|
|
48
53
|
|
|
54
|
+
type = opts[:using] || nullable_type || doc[:type]
|
|
49
55
|
schema = type_resolver.build_exposure_base_schema(type)
|
|
50
|
-
schema = apply_exposure_properties(
|
|
56
|
+
schema = apply_exposure_properties(
|
|
57
|
+
schema, doc, inferred_nullable: !nullable_type.nil? && !opts[:using],
|
|
58
|
+
)
|
|
51
59
|
SchemaConstraints.apply(schema, doc)
|
|
52
60
|
schema
|
|
53
61
|
end
|
|
@@ -110,7 +118,8 @@ module GrapeOAS
|
|
|
110
118
|
|
|
111
119
|
# Determines whether a property should be marked required.
|
|
112
120
|
# Explicit doc[:required] takes precedence; conditional exposures
|
|
113
|
-
# default to false; unconditional exposures
|
|
121
|
+
# default to false; unconditional exposures fall back to
|
|
122
|
+
# GrapeOAS.entity_exposure_required_default (default `true`).
|
|
114
123
|
#
|
|
115
124
|
# @param doc [Hash] normalized documentation hash
|
|
116
125
|
# @param exposure the entity exposure
|
|
@@ -119,7 +128,7 @@ module GrapeOAS
|
|
|
119
128
|
return doc[:required] unless doc[:required].nil?
|
|
120
129
|
return false if conditional?(exposure)
|
|
121
130
|
|
|
122
|
-
|
|
131
|
+
GrapeOAS.entity_exposure_required_default
|
|
123
132
|
end
|
|
124
133
|
|
|
125
134
|
private
|
|
@@ -159,10 +168,28 @@ module GrapeOAS
|
|
|
159
168
|
return prop_schema unless is_array
|
|
160
169
|
|
|
161
170
|
array_schema = ApiModel::Schema.new(type: Constants::SchemaTypes::ARRAY, items: prop_schema)
|
|
171
|
+
if PropertyExtractor.extract_nullable(doc)
|
|
172
|
+
array_schema.nullable = true
|
|
173
|
+
if bare_single_ref_allof?(prop_schema)
|
|
174
|
+
array_schema.items = prop_schema.all_of.first
|
|
175
|
+
else
|
|
176
|
+
prop_schema.nullable = false
|
|
177
|
+
end
|
|
178
|
+
end
|
|
162
179
|
array_schema.examples = doc[:example] if array_valued_example?(doc)
|
|
163
180
|
array_schema
|
|
164
181
|
end
|
|
165
182
|
|
|
183
|
+
def bare_single_ref_allof?(schema)
|
|
184
|
+
return false unless schema.all_of&.one? && schema.all_of.first.canonical_name
|
|
185
|
+
|
|
186
|
+
empty_schema = ApiModel::Schema.new
|
|
187
|
+
# Comparing defaults keeps future schema attributes from being discarded.
|
|
188
|
+
(ApiModel::Schema::VALID_ATTRIBUTES - %i[nullable all_of]).all? do |attribute|
|
|
189
|
+
schema.public_send(attribute) == empty_schema.public_send(attribute)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
166
193
|
# Detects block-based nesting exposures (NestingExposure) that should become
|
|
167
194
|
# inline object schemas. Only triggers when no entity class is via `using:`.
|
|
168
195
|
def nesting_exposure?(exposure)
|
|
@@ -206,8 +233,15 @@ module GrapeOAS
|
|
|
206
233
|
schema
|
|
207
234
|
end
|
|
208
235
|
|
|
209
|
-
def apply_exposure_properties(schema, doc)
|
|
210
|
-
|
|
236
|
+
def apply_exposure_properties(schema, doc, inferred_nullable: false)
|
|
237
|
+
schema = schema.dup if inferred_nullable && !schema.canonical_name
|
|
238
|
+
nullable_false = doc[:nullable] == false ||
|
|
239
|
+
(doc[:x].is_a?(Hash) && doc[:x][:nullable] == false)
|
|
240
|
+
nullable = if (schema.nullable || inferred_nullable) && nullable_false
|
|
241
|
+
false
|
|
242
|
+
else
|
|
243
|
+
schema.nullable || inferred_nullable || PropertyExtractor.extract_nullable(doc)
|
|
244
|
+
end
|
|
211
245
|
if nullable && schema.canonical_name
|
|
212
246
|
# Don't mutate the shared cached entity schema. Create a wrapper with
|
|
213
247
|
# all_of so the exporter emits { nullable: true, allOf: [{ $ref }] }.
|
|
@@ -58,17 +58,19 @@ module GrapeOAS
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def build_items_schema(type_names)
|
|
61
|
-
if
|
|
62
|
-
schema = build_items_for_name(
|
|
61
|
+
if (nullable_type = Constants.nullable_type(type_names))
|
|
62
|
+
schema = build_items_for_name(nullable_type)
|
|
63
63
|
schema.nullable = true
|
|
64
64
|
return schema
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
return build_items_for_name(type_names.first) if type_names.size == 1
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
variants =
|
|
71
|
-
ApiModel::Schema.new(one_of: variants
|
|
69
|
+
nil_types, other_types = type_names.partition { |type| Constants.nil_type?(type) }
|
|
70
|
+
variants = other_types.map { |type| build_items_for_name(type) }
|
|
71
|
+
schema = ApiModel::Schema.new(one_of: variants)
|
|
72
|
+
schema.nullable = true if nil_types.any?
|
|
73
|
+
schema
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
def build_items_for_name(type_name)
|
|
@@ -80,15 +82,6 @@ module GrapeOAS
|
|
|
80
82
|
end
|
|
81
83
|
end
|
|
82
84
|
|
|
83
|
-
def nullable_type_pair?(type_names)
|
|
84
|
-
type_names.size == 2 && type_names.one? { |name| nil_type_name?(name) }
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def nil_type_name?(type_name)
|
|
88
|
-
normalized = type_name.to_s
|
|
89
|
-
normalized == "NilClass" || normalized == "Nil" || normalized.end_with?("::Nil")
|
|
90
|
-
end
|
|
91
|
-
|
|
92
85
|
def build_schema_from_class(klass)
|
|
93
86
|
# First, check if Introspectors can handle this class
|
|
94
87
|
# (e.g., Grape::Entity, Dry::Schema, custom types)
|
data/lib/grape_oas/version.rb
CHANGED
data/lib/grape_oas.rb
CHANGED
|
@@ -91,6 +91,25 @@ module GrapeOAS
|
|
|
91
91
|
|
|
92
92
|
module_function :logger, :logger=
|
|
93
93
|
|
|
94
|
+
# @return [Boolean] whether entity exposures without required metadata
|
|
95
|
+
# default to required
|
|
96
|
+
def entity_exposure_required_default
|
|
97
|
+
return true if @entity_exposure_required_default.nil?
|
|
98
|
+
|
|
99
|
+
@entity_exposure_required_default
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# @param value [true, false, nil] `nil` resets to the default (`true`)
|
|
103
|
+
def entity_exposure_required_default=(value)
|
|
104
|
+
unless value.nil? || value == true || value == false
|
|
105
|
+
raise ArgumentError, "entity_exposure_required_default must be true, false, or nil (got #{value.class})"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
@entity_exposure_required_default = value
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
module_function :entity_exposure_required_default, :entity_exposure_required_default=
|
|
112
|
+
|
|
94
113
|
# Returns the global introspector registry.
|
|
95
114
|
#
|
|
96
115
|
# The registry manages introspectors that build schemas from various sources
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: grape-oas
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrei Subbota
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: grape
|
|
@@ -86,6 +86,7 @@ files:
|
|
|
86
86
|
- lib/grape_oas/exporter.rb
|
|
87
87
|
- lib/grape_oas/exporter/base/operation.rb
|
|
88
88
|
- lib/grape_oas/exporter/base/paths.rb
|
|
89
|
+
- lib/grape_oas/exporter/concerns/enum_normalizer.rb
|
|
89
90
|
- lib/grape_oas/exporter/concerns/schema_indexer.rb
|
|
90
91
|
- lib/grape_oas/exporter/concerns/tag_builder.rb
|
|
91
92
|
- lib/grape_oas/exporter/oas2/operation.rb
|