Summary
For an OpenAPI 3 schema that has no required array AND uses allOf for at least one property, every non-default property in the generated Dart factory is marked required, even though the spec says none should be.
@nestjs/swagger emits allOf for properties typed as a nested DTO (e.g. @ApiPropertyOptional({ type: SomeTypedDto })), so this fires routinely on backends that follow that conventional NestJS pattern.
Version
swagger_parser: 1.43.1
OpenAPI version: 3.0.0
Output: Dart + freezed (json_serializer: freezed, use_freezed3: true)
Minimal reproducer
Spec fragment:
components:
schemas:
Bar:
type: object
properties:
name: { type: string }
required: [name]
Foo:
type: object
properties:
a: { type: string }
b:
allOf:
- $ref: '#/components/schemas/Bar'
Foo has no required array — both a and b should be optional.
Actual generated output
@Freezed()
abstract class Foo with _$Foo {
const factory Foo({
required String a,
required Bar b,
}) = _Foo;
}
Expected
@Freezed()
abstract class Foo with _$Foo {
const factory Foo({
String? a,
Bar? b,
}) = _Foo;
}
Root cause
lib/src/parser/parser/open_api_parser.dart, in _findParametersAndImports:
-
Line 749: var hasAllOfKey = false;
-
Lines 752–758: when the schema has no required key, the parser scans properties and sets hasAllOfKey = true if any property has allOf.
-
Line 800: the final required flag is computed as
isRequired || hasAllOfKey || hasDefaultKey,
So the moment any property uses allOf, every property in the schema is treated as required.
Why this is wrong
allOf is a schema-composition mechanism, not a requiredness signal. A property whose value is { allOf: [ { $ref: '...' } ] } is the standard way to attach a description / example to a typed reference; it says nothing about whether the property is required on its parent object. That information lives only in the parent's required array, exactly as defined in OAS 3.1 §10.2.1 and OAS 3.0 §4.7.24.
A cross-generator sanity check: the same spec fed to swagger-typescript-api correctly generates a?: string; b?: Bar; for Foo. The TS generator only treats fields as required when they appear in required.
Suggested fix
Drop || hasAllOfKey from the expression on line 800. hasAllOfKey is computed only as an input to that expression and can be removed entirely (lines 749, 752–758).
hasDefaultKey is in a similar spot — a default value affects nullability/initialisation semantics, not whether the property is required at the schema level — but I haven't reviewed that path closely and it's not what this issue is about.
Workaround (for downstream users)
Until this is fixed upstream, a post-processor on the generated .dart files can rewrite required Type field, → Type? field, inside the factory constructor of every schema that (a) has no required array and (b) has at least one allOf property.
Summary
For an OpenAPI 3 schema that has no
requiredarray AND usesallOffor at least one property, every non-default property in the generated Dart factory is markedrequired, even though the spec says none should be.@nestjs/swaggeremitsallOffor properties typed as a nested DTO (e.g.@ApiPropertyOptional({ type: SomeTypedDto })), so this fires routinely on backends that follow that conventional NestJS pattern.Version
swagger_parser: 1.43.1OpenAPI version: 3.0.0
Output: Dart + freezed (
json_serializer: freezed,use_freezed3: true)Minimal reproducer
Spec fragment:
Foohas norequiredarray — bothaandbshould be optional.Actual generated output
Expected
Root cause
lib/src/parser/parser/open_api_parser.dart, in_findParametersAndImports:Line 749:
var hasAllOfKey = false;Lines 752–758: when the schema has no
requiredkey, the parser scans properties and setshasAllOfKey = trueif any property hasallOf.Line 800: the final required flag is computed as
So the moment any property uses
allOf, every property in the schema is treated as required.Why this is wrong
allOfis a schema-composition mechanism, not a requiredness signal. A property whose value is{ allOf: [ { $ref: '...' } ] }is the standard way to attach a description / example to a typed reference; it says nothing about whether the property is required on its parent object. That information lives only in the parent'srequiredarray, exactly as defined in OAS 3.1 §10.2.1 and OAS 3.0 §4.7.24.A cross-generator sanity check: the same spec fed to
swagger-typescript-apicorrectly generatesa?: string; b?: Bar;forFoo. The TS generator only treats fields as required when they appear inrequired.Suggested fix
Drop
|| hasAllOfKeyfrom the expression on line 800.hasAllOfKeyis computed only as an input to that expression and can be removed entirely (lines 749, 752–758).hasDefaultKeyis in a similar spot — a default value affects nullability/initialisation semantics, not whether the property is required at the schema level — but I haven't reviewed that path closely and it's not what this issue is about.Workaround (for downstream users)
Until this is fixed upstream, a post-processor on the generated
.dartfiles can rewriterequired Type field,→Type? field,inside the factory constructor of every schema that (a) has norequiredarray and (b) has at least oneallOfproperty.