Skip to content

Commit a0aec70

Browse files
committed
Rename operationDiscriminator to openapi:discriminator and emit as property
1 parent b38f195 commit a0aec70

File tree

12 files changed

+97
-47
lines changed

12 files changed

+97
-47
lines changed

src/Examples/JsonApiDotNetCoreExample/GeneratedSwagger/JsonApiDotNetCoreExample.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5095,10 +5095,13 @@
50955095
},
50965096
"atomicOperation": {
50975097
"required": [
5098-
"operationDiscriminator"
5098+
"openapi:discriminator"
50995099
],
51005100
"type": "object",
51015101
"properties": {
5102+
"openapi:discriminator": {
5103+
"type": "string"
5104+
},
51025105
"meta": {
51035106
"allOf": [
51045107
{
@@ -5109,7 +5112,7 @@
51095112
},
51105113
"additionalProperties": false,
51115114
"discriminator": {
5112-
"propertyName": "operationDiscriminator",
5115+
"propertyName": "openapi:discriminator",
51135116
"mapping": {
51145117
"addPerson": "#/components/schemas/createPersonOperation",
51155118
"addTag": "#/components/schemas/createTagOperation",

src/Examples/OpenApiKiotaClientExample/GeneratedCode/Models/AtomicOperation.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ public partial class AtomicOperation : IBackedModel, IParsable
3030
get { return BackingStore?.Get<global::OpenApiKiotaClientExample.GeneratedCode.Models.Meta>("meta"); }
3131
set { BackingStore?.Set("meta", value); }
3232
}
33+
#endif
34+
/// <summary>The openapiDiscriminator property</summary>
35+
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
36+
#nullable enable
37+
public string? OpenapiDiscriminator
38+
{
39+
get { return BackingStore?.Get<string?>("openapi:discriminator"); }
40+
set { BackingStore?.Set("openapi:discriminator", value); }
41+
}
42+
#nullable restore
43+
#else
44+
public string OpenapiDiscriminator
45+
{
46+
get { return BackingStore?.Get<string>("openapi:discriminator"); }
47+
set { BackingStore?.Set("openapi:discriminator", value); }
48+
}
3349
#endif
3450
/// <summary>
3551
/// Instantiates a new <see cref="global::OpenApiKiotaClientExample.GeneratedCode.Models.AtomicOperation"/> and sets the default values.
@@ -46,7 +62,7 @@ public AtomicOperation()
4662
public static global::OpenApiKiotaClientExample.GeneratedCode.Models.AtomicOperation CreateFromDiscriminatorValue(IParseNode parseNode)
4763
{
4864
_ = parseNode ?? throw new ArgumentNullException(nameof(parseNode));
49-
var mappingValue = parseNode.GetChildNode("operationDiscriminator")?.GetStringValue();
65+
var mappingValue = parseNode.GetChildNode("openapi:discriminator")?.GetStringValue();
5066
return mappingValue switch
5167
{
5268
"addPerson" => new global::OpenApiKiotaClientExample.GeneratedCode.Models.CreatePersonOperation(),
@@ -84,6 +100,7 @@ public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
84100
return new Dictionary<string, Action<IParseNode>>
85101
{
86102
{ "meta", n => { Meta = n.GetObjectValue<global::OpenApiKiotaClientExample.GeneratedCode.Models.Meta>(global::OpenApiKiotaClientExample.GeneratedCode.Models.Meta.CreateFromDiscriminatorValue); } },
103+
{ "openapi:discriminator", n => { OpenapiDiscriminator = n.GetStringValue(); } },
87104
};
88105
}
89106
/// <summary>
@@ -94,6 +111,7 @@ public virtual void Serialize(ISerializationWriter writer)
94111
{
95112
_ = writer ?? throw new ArgumentNullException(nameof(writer));
96113
writer.WriteObjectValue<global::OpenApiKiotaClientExample.GeneratedCode.Models.Meta>("meta", Meta);
114+
writer.WriteStringValue("openapi:discriminator", OpenapiDiscriminator);
97115
}
98116
}
99117
}

src/JsonApiDotNetCore.OpenApi.Swashbuckle/ConfigureSwaggerGenOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public void Configure(SwaggerGenOptions options)
4949
options.UseAllOfToExtendReferenceSchemas();
5050

5151
options.UseAllOfForInheritance();
52-
options.SelectDiscriminatorNameUsing(_ => "type");
52+
options.SelectDiscriminatorNameUsing(_ => JsonApiPropertyName.Type);
5353
options.SelectDiscriminatorValueUsing(clrType => _resourceGraph.GetResourceType(clrType).PublicName);
5454
options.SelectSubTypesUsing(SelectDerivedTypes);
5555

src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaIdSelector.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ internal sealed class JsonApiSchemaIdSelector
1515
private const string ResourceTypeSchemaIdTemplate = "[ResourceName] Resource Type";
1616
private const string MetaSchemaIdTemplate = "Meta";
1717

18-
private const string AtomicOperationDiscriminatorNameTemplate = "Operation Discriminator";
1918
private const string ResourceAtomicOperationDiscriminatorValueTemplate = "[OperationCode] [ResourceName]";
2019
private const string UpdateRelationshipAtomicOperationDiscriminatorValueTemplate = "Update [ResourceName] [RelationshipName]";
2120
private const string AddToRelationshipAtomicOperationDiscriminatorValueTemplate = "Add To [ResourceName] [RelationshipName]";
@@ -154,11 +153,6 @@ public string GetAtomicOperationCodeSchemaId(AtomicOperationCode operationCode)
154153
return ApplySchemaTemplate("[OperationCode] Operation Code", null, null, operationCode);
155154
}
156155

157-
public string GetAtomicOperationDiscriminatorName()
158-
{
159-
return ApplySchemaTemplate(AtomicOperationDiscriminatorNameTemplate, null, null, null);
160-
}
161-
162156
public string GetAtomicOperationDiscriminatorValue(AtomicOperationCode operationCode, ResourceType resourceType)
163157
{
164158
ArgumentGuard.NotNull(resourceType);

src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AbstractAtomicOperationSchemaGenerator.cs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiObjects.AtomicOperations;
22
using Microsoft.OpenApi.Any;
3-
using Microsoft.OpenApi.Interfaces;
43
using Microsoft.OpenApi.Models;
54
using Swashbuckle.AspNetCore.SwaggerGen;
65

76
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
87

98
internal sealed class AbstractAtomicOperationSchemaGenerator
109
{
10+
// The discriminator only exists to guide OpenAPI codegen of request bodies. It is silently ignored by the JSON:API server.
11+
private const string DiscriminatorPropertyName = "openapi:discriminator";
12+
1113
private static readonly Type AtomicOperationAbstractType = typeof(AtomicOperation);
1214

1315
private readonly MetaSchemaGenerator _metaSchemaGenerator;
@@ -31,27 +33,27 @@ public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository)
3133
return referenceSchema;
3234
}
3335

34-
// The discriminator only exists to guide OpenAPI codegen. The property is ignored by JsonApiDotNetCore.
35-
string discriminatorPropertyName = _schemaIdSelector.GetAtomicOperationDiscriminatorName();
36-
37-
referenceSchema = _metaSchemaGenerator.GenerateSchema(schemaRepository);
38-
string metaSchemaId = referenceSchema.Reference.Id;
36+
OpenApiSchema referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository);
3937

4038
var fullSchema = new OpenApiSchema
4139
{
4240
Type = "object",
43-
Required = new SortedSet<string>([discriminatorPropertyName]),
41+
Required = new SortedSet<string>([DiscriminatorPropertyName]),
4442
Properties = new Dictionary<string, OpenApiSchema>
4543
{
46-
[metaSchemaId] = referenceSchema.WrapInExtendedSchema()
44+
[DiscriminatorPropertyName] = new()
45+
{
46+
Type = "string"
47+
},
48+
[referenceSchemaForMeta.Reference.Id] = referenceSchemaForMeta.WrapInExtendedSchema()
4749
},
4850
AdditionalPropertiesAllowed = false,
4951
Discriminator = new OpenApiDiscriminator
5052
{
51-
PropertyName = discriminatorPropertyName,
53+
PropertyName = DiscriminatorPropertyName,
5254
Mapping = new SortedDictionary<string, string>(StringComparer.Ordinal)
5355
},
54-
Extensions = new Dictionary<string, IOpenApiExtension>
56+
Extensions =
5557
{
5658
["x-abstract"] = new OpenApiBoolean(true)
5759
}
@@ -70,10 +72,12 @@ public void MapDiscriminator(OpenApiSchema referenceSchemaForOperation, string d
7072
ArgumentGuard.NotNull(referenceSchemaForOperation);
7173
ArgumentGuard.NotNull(schemaRepository);
7274

73-
if (schemaRepository.TryLookupByType(AtomicOperationAbstractType, out OpenApiSchema? referenceSchemaForAbstractOperation))
75+
if (!schemaRepository.TryLookupByType(AtomicOperationAbstractType, out OpenApiSchema? referenceSchemaForAbstractOperation))
7476
{
75-
OpenApiSchema fullSchemaForAbstractOperation = schemaRepository.Schemas[referenceSchemaForAbstractOperation.Reference.Id];
76-
fullSchemaForAbstractOperation.Discriminator.Mapping[discriminatorValue] = referenceSchemaForOperation.Reference.ReferenceV3;
77+
throw new UnreachableCodeException();
7778
}
79+
80+
OpenApiSchema fullSchemaForAbstractOperation = schemaRepository.Schemas[referenceSchemaForAbstractOperation.Reference.Id];
81+
fullSchemaForAbstractOperation.Discriminator.Mapping.Add(discriminatorValue, referenceSchemaForOperation.Reference.ReferenceV3);
7882
}
7983
}

src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AbstractResourceDataSchemaGenerator.cs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiObjects.ResourceObjects;
33
using JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents;
44
using Microsoft.OpenApi.Any;
5-
using Microsoft.OpenApi.Interfaces;
65
using Microsoft.OpenApi.Models;
76
using Swashbuckle.AspNetCore.SwaggerGen;
87

@@ -35,14 +34,11 @@ public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository)
3534

3635
var fullSchema = new OpenApiSchema
3736
{
38-
Required = new HashSet<string>
39-
{
40-
"type"
41-
},
37+
Required = new SortedSet<string>([JsonApiPropertyName.Type]),
4238
Type = "object",
4339
Properties = new Dictionary<string, OpenApiSchema>
4440
{
45-
["type"] = new()
41+
[JsonApiPropertyName.Type] = new()
4642
{
4743
MinLength = 1,
4844
Type = "string"
@@ -51,10 +47,10 @@ public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository)
5147
AdditionalPropertiesAllowed = false,
5248
Discriminator = new OpenApiDiscriminator
5349
{
54-
PropertyName = "type",
50+
PropertyName = JsonApiPropertyName.Type,
5551
Mapping = new SortedDictionary<string, string>(StringComparer.Ordinal)
5652
},
57-
Extensions = new Dictionary<string, IOpenApiExtension>
53+
Extensions =
5854
{
5955
["x-abstract"] = new OpenApiBoolean(true)
6056
}
@@ -78,13 +74,15 @@ public void MapDiscriminator(Type resourceDataConstructedType, OpenApiSchema ref
7874

7975
if (resourceTypeInfo.ResourceDataOpenType == typeof(ResourceDataInResponse<>))
8076
{
81-
if (schemaRepository.TryLookupByType(ResourceDataAbstractType, out OpenApiSchema? referenceSchemaForAbstractResourceData))
77+
if (!schemaRepository.TryLookupByType(ResourceDataAbstractType, out OpenApiSchema? referenceSchemaForAbstractResourceData))
8278
{
83-
OpenApiSchema fullSchemaForAbstractResourceData = schemaRepository.Schemas[referenceSchemaForAbstractResourceData.Reference.Id];
84-
85-
fullSchemaForAbstractResourceData.Discriminator.Mapping[resourceTypeInfo.ResourceType.PublicName] =
86-
referenceSchemaForResourceData.Reference.ReferenceV3;
79+
throw new UnreachableCodeException();
8780
}
81+
82+
OpenApiSchema fullSchemaForAbstractResourceData = schemaRepository.Schemas[referenceSchemaForAbstractResourceData.Reference.Id];
83+
84+
fullSchemaForAbstractResourceData.Discriminator.Mapping[resourceTypeInfo.ResourceType.PublicName] =
85+
referenceSchemaForResourceData.Reference.ReferenceV3;
8886
}
8987
}
9088
}

test/OpenApiKiotaEndToEndTests/AtomicOperations/GeneratedCode/Models/AtomicOperation.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ public partial class AtomicOperation : IBackedModel, IParsable
3030
get { return BackingStore?.Get<global::OpenApiKiotaEndToEndTests.AtomicOperations.GeneratedCode.Models.Meta>("meta"); }
3131
set { BackingStore?.Set("meta", value); }
3232
}
33+
#endif
34+
/// <summary>The openapiDiscriminator property</summary>
35+
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
36+
#nullable enable
37+
public string? OpenapiDiscriminator
38+
{
39+
get { return BackingStore?.Get<string?>("openapi:discriminator"); }
40+
set { BackingStore?.Set("openapi:discriminator", value); }
41+
}
42+
#nullable restore
43+
#else
44+
public string OpenapiDiscriminator
45+
{
46+
get { return BackingStore?.Get<string>("openapi:discriminator"); }
47+
set { BackingStore?.Set("openapi:discriminator", value); }
48+
}
3349
#endif
3450
/// <summary>
3551
/// Instantiates a new <see cref="global::OpenApiKiotaEndToEndTests.AtomicOperations.GeneratedCode.Models.AtomicOperation"/> and sets the default values.
@@ -46,7 +62,7 @@ public AtomicOperation()
4662
public static global::OpenApiKiotaEndToEndTests.AtomicOperations.GeneratedCode.Models.AtomicOperation CreateFromDiscriminatorValue(IParseNode parseNode)
4763
{
4864
_ = parseNode ?? throw new ArgumentNullException(nameof(parseNode));
49-
var mappingValue = parseNode.GetChildNode("operationDiscriminator")?.GetStringValue();
65+
var mappingValue = parseNode.GetChildNode("openapi:discriminator")?.GetStringValue();
5066
return mappingValue switch
5167
{
5268
"addCourse" => new global::OpenApiKiotaEndToEndTests.AtomicOperations.GeneratedCode.Models.CreateCourseOperation(),
@@ -87,6 +103,7 @@ public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
87103
return new Dictionary<string, Action<IParseNode>>
88104
{
89105
{ "meta", n => { Meta = n.GetObjectValue<global::OpenApiKiotaEndToEndTests.AtomicOperations.GeneratedCode.Models.Meta>(global::OpenApiKiotaEndToEndTests.AtomicOperations.GeneratedCode.Models.Meta.CreateFromDiscriminatorValue); } },
106+
{ "openapi:discriminator", n => { OpenapiDiscriminator = n.GetStringValue(); } },
90107
};
91108
}
92109
/// <summary>
@@ -97,6 +114,7 @@ public virtual void Serialize(ISerializationWriter writer)
97114
{
98115
_ = writer ?? throw new ArgumentNullException(nameof(writer));
99116
writer.WriteObjectValue<global::OpenApiKiotaEndToEndTests.AtomicOperations.GeneratedCode.Models.Meta>("meta", Meta);
117+
writer.WriteStringValue("openapi:discriminator", OpenapiDiscriminator);
100118
}
101119
}
102120
}

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6512,10 +6512,13 @@
65126512
},
65136513
"atomicOperation": {
65146514
"required": [
6515-
"operationDiscriminator"
6515+
"openapi:discriminator"
65166516
],
65176517
"type": "object",
65186518
"properties": {
6519+
"openapi:discriminator": {
6520+
"type": "string"
6521+
},
65196522
"meta": {
65206523
"allOf": [
65216524
{
@@ -6526,7 +6529,7 @@
65266529
},
65276530
"additionalProperties": false,
65286531
"discriminator": {
6529-
"propertyName": "operationDiscriminator",
6532+
"propertyName": "openapi:discriminator",
65306533
"mapping": {
65316534
"addCourse": "#/components/schemas/createCourseOperation",
65326535
"addEnrollment": "#/components/schemas/createEnrollmentOperation",

test/OpenApiTests/AtomicOperations/OperationsTests.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,13 @@ public async Task Operations_request_component_schemas_are_exposed()
160160
schemasElement.Should().ContainPath("atomicOperation").Should().BeJson("""
161161
{
162162
"required": [
163-
"operationDiscriminator"
163+
"openapi:discriminator"
164164
],
165165
"type": "object",
166166
"properties": {
167+
"openapi:discriminator": {
168+
"type": "string"
169+
},
167170
"meta": {
168171
"allOf": [
169172
{
@@ -174,7 +177,7 @@ public async Task Operations_request_component_schemas_are_exposed()
174177
},
175178
"additionalProperties": false,
176179
"discriminator": {
177-
"propertyName": "operationDiscriminator",
180+
"propertyName": "openapi:discriminator",
178181
"mapping": {
179182
"addCourse": "#/components/schemas/createCourseOperation",
180183
"addEnrollment": "#/components/schemas/createEnrollmentOperation",

test/OpenApiTests/NamingConventions/CamelCase/GeneratedSwagger/swagger.g.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2709,10 +2709,13 @@
27092709
},
27102710
"atomicOperation": {
27112711
"required": [
2712-
"operationDiscriminator"
2712+
"openapi:discriminator"
27132713
],
27142714
"type": "object",
27152715
"properties": {
2716+
"openapi:discriminator": {
2717+
"type": "string"
2718+
},
27162719
"meta": {
27172720
"allOf": [
27182721
{
@@ -2723,7 +2726,7 @@
27232726
},
27242727
"additionalProperties": false,
27252728
"discriminator": {
2726-
"propertyName": "operationDiscriminator",
2729+
"propertyName": "openapi:discriminator",
27272730
"mapping": {
27282731
"addStaffMember": "#/components/schemas/createStaffMemberOperation",
27292732
"addSupermarket": "#/components/schemas/createSupermarketOperation",

0 commit comments

Comments
 (0)