Skip to content

Commit 6178c58

Browse files
committed
Cleanup allOf wrapping/unwrapping
1 parent 9a90ef8 commit 6178c58

File tree

26 files changed

+492
-127
lines changed

26 files changed

+492
-127
lines changed

src/Examples/JsonApiDotNetCoreExample/GeneratedSwagger/JsonApiDotNetCoreExample.json

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4895,7 +4895,11 @@
48954895
"type": "object",
48964896
"properties": {
48974897
"type": {
4898-
"$ref": "#/components/schemas/personResourceType"
4898+
"allOf": [
4899+
{
4900+
"$ref": "#/components/schemas/personResourceType"
4901+
}
4902+
]
48994903
},
49004904
"attributes": {
49014905
"allOf": [
@@ -4921,7 +4925,11 @@
49214925
"type": "object",
49224926
"properties": {
49234927
"type": {
4924-
"$ref": "#/components/schemas/tagResourceType"
4928+
"allOf": [
4929+
{
4930+
"$ref": "#/components/schemas/tagResourceType"
4931+
}
4932+
]
49254933
},
49264934
"attributes": {
49274935
"allOf": [
@@ -4947,7 +4955,11 @@
49474955
"type": "object",
49484956
"properties": {
49494957
"type": {
4950-
"$ref": "#/components/schemas/todoItemResourceType"
4958+
"allOf": [
4959+
{
4960+
"$ref": "#/components/schemas/todoItemResourceType"
4961+
}
4962+
]
49514963
},
49524964
"attributes": {
49534965
"allOf": [
@@ -5001,7 +5013,11 @@
50015013
"type": "object",
50025014
"properties": {
50035015
"type": {
5004-
"$ref": "#/components/schemas/personResourceType"
5016+
"allOf": [
5017+
{
5018+
"$ref": "#/components/schemas/personResourceType"
5019+
}
5020+
]
50055021
},
50065022
"id": {
50075023
"minLength": 1,
@@ -5032,7 +5048,11 @@
50325048
"type": "object",
50335049
"properties": {
50345050
"type": {
5035-
"$ref": "#/components/schemas/tagResourceType"
5051+
"allOf": [
5052+
{
5053+
"$ref": "#/components/schemas/tagResourceType"
5054+
}
5055+
]
50365056
},
50375057
"id": {
50385058
"minLength": 1,
@@ -5063,7 +5083,11 @@
50635083
"type": "object",
50645084
"properties": {
50655085
"type": {
5066-
"$ref": "#/components/schemas/todoItemResourceType"
5086+
"allOf": [
5087+
{
5088+
"$ref": "#/components/schemas/todoItemResourceType"
5089+
}
5090+
]
50675091
},
50685092
"id": {
50695093
"minLength": 1,
@@ -5432,7 +5456,11 @@
54325456
"type": "object",
54335457
"properties": {
54345458
"type": {
5435-
"$ref": "#/components/schemas/personResourceType"
5459+
"allOf": [
5460+
{
5461+
"$ref": "#/components/schemas/personResourceType"
5462+
}
5463+
]
54365464
},
54375465
"id": {
54385466
"minLength": 1,
@@ -5891,7 +5919,11 @@
58915919
"type": "object",
58925920
"properties": {
58935921
"type": {
5894-
"$ref": "#/components/schemas/tagResourceType"
5922+
"allOf": [
5923+
{
5924+
"$ref": "#/components/schemas/tagResourceType"
5925+
}
5926+
]
58955927
},
58965928
"id": {
58975929
"minLength": 1,
@@ -6228,7 +6260,11 @@
62286260
"type": "object",
62296261
"properties": {
62306262
"type": {
6231-
"$ref": "#/components/schemas/todoItemResourceType"
6263+
"allOf": [
6264+
{
6265+
"$ref": "#/components/schemas/todoItemResourceType"
6266+
}
6267+
]
62326268
},
62336269
"id": {
62346270
"minLength": 1,

src/JsonApiDotNetCore.OpenApi/OpenApiSchemaExtensions.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,25 @@ public static void ReorderProperties(this OpenApiSchema fullSchema, IEnumerable<
2727
fullSchema.Properties = propertiesInOrder;
2828
}
2929

30-
public static OpenApiSchema UnwrapExtendedReferenceSchema(this OpenApiSchema source)
30+
public static OpenApiSchema WrapInExtendedSchema(this OpenApiSchema source)
3131
{
3232
ArgumentGuard.NotNull(source);
3333

34-
if (source.AllOf.Count != 1)
34+
return new OpenApiSchema
3535
{
36-
throw new InvalidOperationException($"Schema '{nameof(source)}' should not contain multiple entries in '{nameof(source.AllOf)}' ");
36+
AllOf = [source]
37+
};
38+
}
39+
40+
public static OpenApiSchema UnwrapLastExtendedSchema(this OpenApiSchema source)
41+
{
42+
ArgumentGuard.NotNull(source);
43+
44+
if (source.AllOf is { Count: > 0 })
45+
{
46+
return source.AllOf.Last();
3747
}
3848

39-
return source.AllOf.Single();
49+
return source;
4050
}
4151
}

src/JsonApiDotNetCore.OpenApi/SwaggerComponents/DocumentSchemaGenerator.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,7 @@ private void GenerateErrorObjectSchema(SchemaRepository schemaRepository)
7575
OpenApiSchema fullSchemaForErrorObject = schemaRepository.Schemas[referenceSchemaForErrorObject.Reference.Id];
7676

7777
OpenApiSchema referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository);
78-
79-
fullSchemaForErrorObject.Properties[JsonApiPropertyName.Meta] = new OpenApiSchema
80-
{
81-
AllOf = [referenceSchemaForMeta]
82-
};
78+
fullSchemaForErrorObject.Properties[JsonApiPropertyName.Meta] = referenceSchemaForMeta.WrapInExtendedSchema();
8379
}
8480

8581
private OpenApiSchema GenerateJsonApiDocumentSchema(Type documentType, SchemaRepository schemaRepository)

src/JsonApiDotNetCore.OpenApi/SwaggerComponents/LinksVisibilitySchemaGenerator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ private void UpdateLinksProperty(OpenApiSchema fullSchemaForLinksContainer, Link
115115
}
116116
else if (visibleLinkTypes != possibleLinkTypes)
117117
{
118-
OpenApiSchema referenceSchemaForLinks = fullSchemaForLinksContainer.Properties[JsonApiPropertyName.Links];
119-
string linksSchemaId = referenceSchemaForLinks.AllOf[0].Reference.Id;
118+
OpenApiSchema referenceSchemaForLinks = fullSchemaForLinksContainer.Properties[JsonApiPropertyName.Links].UnwrapLastExtendedSchema();
119+
string linksSchemaId = referenceSchemaForLinks.Reference.Id;
120120

121121
if (schemaRepository.Schemas.TryGetValue(linksSchemaId, out OpenApiSchema? fullSchemaForLinks))
122122
{

src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceDataSchemaGenerator.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ public OpenApiSchema GenerateSchema(Type resourceDataConstructedType, SchemaRepo
7575
var fieldSchemaBuilder = new ResourceFieldSchemaBuilder(_defaultSchemaGenerator, _resourceIdentifierSchemaGenerator, _linksVisibilitySchemaGenerator,
7676
_resourceFieldValidationMetadataProvider, _relationshipTypeFactory, resourceTypeInfo);
7777

78-
OpenApiSchema effectiveFullSchemaForResourceData =
79-
fullSchemaForResourceData.AllOf.Count == 0 ? fullSchemaForResourceData : fullSchemaForResourceData.AllOf[1];
78+
OpenApiSchema effectiveFullSchemaForResourceData = fullSchemaForResourceData.UnwrapLastExtendedSchema();
8079

8180
if (effectiveFullSchemaForResourceData == fullSchemaForResourceData)
8281
{
@@ -118,12 +117,13 @@ private void AdaptResourceIdentity(ResourceTypeInfo resourceTypeInfo, OpenApiSch
118117

119118
private void SetResourceType(OpenApiSchema fullSchemaForResourceData, ResourceType resourceType, SchemaRepository schemaRepository)
120119
{
121-
fullSchemaForResourceData.Properties[JsonApiPropertyName.Type] = _resourceTypeSchemaGenerator.Get(resourceType, schemaRepository);
120+
OpenApiSchema referenceSchema = _resourceTypeSchemaGenerator.Get(resourceType, schemaRepository);
121+
fullSchemaForResourceData.Properties[JsonApiPropertyName.Type] = referenceSchema.WrapInExtendedSchema();
122122
}
123123

124124
private void SetResourceAttributes(OpenApiSchema fullSchemaForResourceData, ResourceFieldSchemaBuilder builder, SchemaRepository schemaRepository)
125125
{
126-
OpenApiSchema referenceSchemaForAttributes = fullSchemaForResourceData.Properties[JsonApiPropertyName.Attributes].UnwrapExtendedReferenceSchema();
126+
OpenApiSchema referenceSchemaForAttributes = fullSchemaForResourceData.Properties[JsonApiPropertyName.Attributes].UnwrapLastExtendedSchema();
127127
OpenApiSchema fullSchemaForAttributes = schemaRepository.Schemas[referenceSchemaForAttributes.Reference.Id];
128128

129129
builder.SetMembersOfAttributes(fullSchemaForAttributes, schemaRepository);
@@ -140,7 +140,7 @@ private void SetResourceAttributes(OpenApiSchema fullSchemaForResourceData, Reso
140140

141141
private void SetResourceRelationships(OpenApiSchema fullSchemaForResourceData, ResourceFieldSchemaBuilder builder, SchemaRepository schemaRepository)
142142
{
143-
OpenApiSchema referenceSchemaForRelationships = fullSchemaForResourceData.Properties[JsonApiPropertyName.Relationships].UnwrapExtendedReferenceSchema();
143+
OpenApiSchema referenceSchemaForRelationships = fullSchemaForResourceData.Properties[JsonApiPropertyName.Relationships].UnwrapLastExtendedSchema();
144144
OpenApiSchema fullSchemaForRelationships = schemaRepository.Schemas[referenceSchemaForRelationships.Reference.Id];
145145

146146
builder.SetMembersOfRelationships(fullSchemaForRelationships, schemaRepository);

src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldSchemaBuilder.cs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,12 @@ public void SetMembersOfAttributes(OpenApiSchema fullSchemaForAttributes, Schema
6666

6767
if (matchingAttribute != null && matchingAttribute.Capabilities.HasFlag(requiredCapability))
6868
{
69-
bool isPrimitiveOpenApiType = resourceFieldSchema.AllOf.IsNullOrEmpty();
69+
bool isInlineSchemaType = resourceFieldSchema.AllOf.Count == 0;
7070

71-
// Types like enum and complex attributes are not primitive and handled as reference schemas.
72-
if (!isPrimitiveOpenApiType)
71+
// Schemas for types like enum and complex attributes are handled as reference schemas.
72+
if (!isInlineSchemaType)
7373
{
74-
EnsureAttributeSchemaIsExposed(resourceFieldSchema, matchingAttribute, schemaRepository);
74+
EnsureAttributeSchemaIsExposed(resourceFieldSchema.UnwrapLastExtendedSchema(), matchingAttribute, schemaRepository);
7575
}
7676

7777
fullSchemaForAttributes.Properties[matchingAttribute.PublicName] = resourceFieldSchema;
@@ -104,7 +104,7 @@ private void EnsureAttributeSchemaIsExposed(OpenApiSchema attributeReferenceSche
104104
return;
105105
}
106106

107-
string schemaId = attributeReferenceSchema.UnwrapExtendedReferenceSchema().Reference.Id;
107+
string schemaId = attributeReferenceSchema.Reference.Id;
108108

109109
OpenApiSchema fullSchema = _resourceSchemaRepository.Schemas[schemaId];
110110
schemaRepository.AddDefinition(schemaId, fullSchema);
@@ -156,14 +156,8 @@ private void AddRelationshipSchemaToResourceData(RelationshipAttribute relations
156156
OpenApiSchema referenceSchemaForRelationship = GetReferenceSchemaForRelationship(relationshipSchemaType, schemaRepository) ??
157157
CreateRelationshipReferenceSchema(relationshipSchemaType, schemaRepository);
158158

159-
var extendedReferenceSchemaForRelationship = new OpenApiSchema
160-
{
161-
AllOf = new List<OpenApiSchema>
162-
{
163-
referenceSchemaForRelationship
164-
},
165-
Description = _resourceDocumentationReader.GetDocumentationForRelationship(relationship)
166-
};
159+
OpenApiSchema extendedReferenceSchemaForRelationship = referenceSchemaForRelationship.WrapInExtendedSchema();
160+
extendedReferenceSchemaForRelationship.Description = _resourceDocumentationReader.GetDocumentationForRelationship(relationship);
167161

168162
fullSchemaForRelationships.Properties.Add(relationship.PublicName, extendedReferenceSchemaForRelationship);
169163

src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceIdentifierSchemaGenerator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ public OpenApiSchema GenerateSchema(ResourceType resourceType, SchemaRepository
3131
referenceSchemaForIdentifier = _defaultSchemaGenerator.GenerateSchema(resourceIdentifierConstructedType, schemaRepository);
3232
OpenApiSchema fullSchemaForIdentifier = schemaRepository.Schemas[referenceSchemaForIdentifier.Reference.Id];
3333

34-
fullSchemaForIdentifier.Properties[JsonApiPropertyName.Type] = _resourceTypeSchemaGenerator.Get(resourceType, schemaRepository);
34+
OpenApiSchema referenceSchemaForResourceType = _resourceTypeSchemaGenerator.Get(resourceType, schemaRepository);
35+
fullSchemaForIdentifier.Properties[JsonApiPropertyName.Type] = referenceSchemaForResourceType.WrapInExtendedSchema();
3536
}
3637

3738
return referenceSchemaForIdentifier;

test/OpenApiTests/ClientIdGenerationModes/GeneratedSwagger/swagger.g.json

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,11 @@
430430
"type": "object",
431431
"properties": {
432432
"type": {
433-
"$ref": "#/components/schemas/gameResourceType"
433+
"allOf": [
434+
{
435+
"$ref": "#/components/schemas/gameResourceType"
436+
}
437+
]
434438
},
435439
"id": {
436440
"minLength": 1,
@@ -453,7 +457,11 @@
453457
"type": "object",
454458
"properties": {
455459
"type": {
456-
"$ref": "#/components/schemas/playerGroupResourceType"
460+
"allOf": [
461+
{
462+
"$ref": "#/components/schemas/playerGroupResourceType"
463+
}
464+
]
457465
},
458466
"attributes": {
459467
"allOf": [
@@ -480,7 +488,11 @@
480488
"type": "object",
481489
"properties": {
482490
"type": {
483-
"$ref": "#/components/schemas/playerResourceType"
491+
"allOf": [
492+
{
493+
"$ref": "#/components/schemas/playerResourceType"
494+
}
495+
]
484496
},
485497
"id": {
486498
"minLength": 1,
@@ -708,7 +720,11 @@
708720
"type": "object",
709721
"properties": {
710722
"type": {
711-
"$ref": "#/components/schemas/gameResourceType"
723+
"allOf": [
724+
{
725+
"$ref": "#/components/schemas/gameResourceType"
726+
}
727+
]
712728
},
713729
"id": {
714730
"minLength": 1,
@@ -877,7 +893,11 @@
877893
"type": "object",
878894
"properties": {
879895
"type": {
880-
"$ref": "#/components/schemas/playerGroupResourceType"
896+
"allOf": [
897+
{
898+
"$ref": "#/components/schemas/playerGroupResourceType"
899+
}
900+
]
881901
},
882902
"id": {
883903
"minLength": 1,
@@ -951,7 +971,11 @@
951971
"type": "object",
952972
"properties": {
953973
"type": {
954-
"$ref": "#/components/schemas/playerResourceType"
974+
"allOf": [
975+
{
976+
"$ref": "#/components/schemas/playerResourceType"
977+
}
978+
]
955979
},
956980
"id": {
957981
"minLength": 1,

test/OpenApiTests/Headers/GeneratedSwagger/swagger.g.json

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,7 +1328,11 @@
13281328
"type": "object",
13291329
"properties": {
13301330
"type": {
1331-
"$ref": "#/components/schemas/countryResourceType"
1331+
"allOf": [
1332+
{
1333+
"$ref": "#/components/schemas/countryResourceType"
1334+
}
1335+
]
13321336
},
13331337
"attributes": {
13341338
"allOf": [
@@ -1381,7 +1385,11 @@
13811385
"type": "object",
13821386
"properties": {
13831387
"type": {
1384-
"$ref": "#/components/schemas/countryResourceType"
1388+
"allOf": [
1389+
{
1390+
"$ref": "#/components/schemas/countryResourceType"
1391+
}
1392+
]
13851393
},
13861394
"id": {
13871395
"minLength": 1,
@@ -1617,7 +1625,11 @@
16171625
"type": "object",
16181626
"properties": {
16191627
"type": {
1620-
"$ref": "#/components/schemas/languageResourceType"
1628+
"allOf": [
1629+
{
1630+
"$ref": "#/components/schemas/languageResourceType"
1631+
}
1632+
]
16211633
},
16221634
"id": {
16231635
"minLength": 1,

0 commit comments

Comments
 (0)