diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index bc38da9f39..0a16709d8d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -10,9 +10,9 @@ name: Build
on:
push:
- branches: [ 'master', 'release/**' ]
+ branches: [ 'master', 'release/**', 'net10-preview' ]
pull_request:
- branches: [ 'master', 'release/**' ]
+ branches: [ 'master', 'release/**', 'net10-preview' ]
release:
types: [published]
@@ -48,6 +48,11 @@ jobs:
dotnet-version: |
8.0.*
9.0.*
+ - name: Setup .NET 10 preview
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.*
+ dotnet-quality: 'preview'
- name: Show installed versions
shell: pwsh
run: |
@@ -166,6 +171,11 @@ jobs:
dotnet-version: |
8.0.*
9.0.*
+ - name: Setup .NET 10 preview
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.*
+ dotnet-quality: 'preview'
- name: Git checkout
uses: actions/checkout@v4
- name: Restore tools
@@ -221,6 +231,11 @@ jobs:
dotnet-version: |
8.0.*
9.0.*
+ - name: Setup .NET 10 preview
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.*
+ dotnet-quality: 'preview'
- name: Git checkout
uses: actions/checkout@v4
with:
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 508d210158..455071b122 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -29,6 +29,11 @@ jobs:
dotnet-version: |
8.0.*
9.0.*
+ - name: Setup .NET 10 preview
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.*
+ dotnet-quality: 'preview'
- name: Git checkout
uses: actions/checkout@v4
- name: Initialize CodeQL
diff --git a/Directory.Build.props b/Directory.Build.props
index 1ef255f56e..4664c01565 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -15,6 +15,12 @@
direct
+
+
+ true
+ $(NoWarn);NU1903;NU5104;NU1608
+
+
+ 10.0.*-*
+ 9.0.0-pr.3283.*
+
+
+ 10.0.*-*
+ 9.0.0-pr.3283.*
+ 2.0.0-preview.21
+ 10.0.*-*
+ 10.0.*-*
+ 9.0.*-*
+
+
N/A
diff --git a/src/Examples/DapperExample/DapperExample.csproj b/src/Examples/DapperExample/DapperExample.csproj
index ed7bd358eb..b2c71ee0f8 100644
--- a/src/Examples/DapperExample/DapperExample.csproj
+++ b/src/Examples/DapperExample/DapperExample.csproj
@@ -1,6 +1,6 @@
- net9.0;net8.0
+ net10.0;net9.0;net8.0
@@ -14,6 +14,7 @@
+
diff --git a/src/Examples/DatabasePerTenantExample/DatabasePerTenantExample.csproj b/src/Examples/DatabasePerTenantExample/DatabasePerTenantExample.csproj
index 3edc993428..c7cee804b1 100644
--- a/src/Examples/DatabasePerTenantExample/DatabasePerTenantExample.csproj
+++ b/src/Examples/DatabasePerTenantExample/DatabasePerTenantExample.csproj
@@ -1,6 +1,6 @@
- net9.0;net8.0
+ net10.0;net9.0;net8.0
diff --git a/src/Examples/GettingStarted/GettingStarted.csproj b/src/Examples/GettingStarted/GettingStarted.csproj
index 611aeb37a5..806fdf45a5 100644
--- a/src/Examples/GettingStarted/GettingStarted.csproj
+++ b/src/Examples/GettingStarted/GettingStarted.csproj
@@ -1,6 +1,6 @@
- net9.0;net8.0
+ net10.0;net9.0;net8.0
diff --git a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj
index 768a2de827..319c72b262 100644
--- a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj
+++ b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj
@@ -1,6 +1,6 @@
- net9.0;net8.0
+ net10.0
true
GeneratedSwagger
diff --git a/src/Examples/JsonApiDotNetCoreExample/SetOpenApiServerAtBuildTimeFilter.cs b/src/Examples/JsonApiDotNetCoreExample/SetOpenApiServerAtBuildTimeFilter.cs
index 894c0d0966..e790f70b6a 100644
--- a/src/Examples/JsonApiDotNetCoreExample/SetOpenApiServerAtBuildTimeFilter.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/SetOpenApiServerAtBuildTimeFilter.cs
@@ -16,6 +16,8 @@ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
if (_httpContextAccessor.HttpContext == null)
{
+ swaggerDoc.Servers ??= [];
+
swaggerDoc.Servers.Add(new OpenApiServer
{
Url = "https://localhost:44340"
diff --git a/src/Examples/MultiDbContextExample/MultiDbContextExample.csproj b/src/Examples/MultiDbContextExample/MultiDbContextExample.csproj
index 611aeb37a5..806fdf45a5 100644
--- a/src/Examples/MultiDbContextExample/MultiDbContextExample.csproj
+++ b/src/Examples/MultiDbContextExample/MultiDbContextExample.csproj
@@ -1,6 +1,6 @@
- net9.0;net8.0
+ net10.0;net9.0;net8.0
diff --git a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj
index 15a485c08f..e50874f733 100644
--- a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj
+++ b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj
@@ -1,6 +1,6 @@
- net9.0;net8.0
+ net10.0;net9.0;net8.0
diff --git a/src/Examples/OpenApiKiotaClientExample/OpenApiKiotaClientExample.csproj b/src/Examples/OpenApiKiotaClientExample/OpenApiKiotaClientExample.csproj
index 8f65b2b688..8dd3e2e4df 100644
--- a/src/Examples/OpenApiKiotaClientExample/OpenApiKiotaClientExample.csproj
+++ b/src/Examples/OpenApiKiotaClientExample/OpenApiKiotaClientExample.csproj
@@ -1,6 +1,6 @@
- net9.0
+ net10.0
diff --git a/src/Examples/OpenApiNSwagClientExample/OpenApiNSwagClientExample.csproj b/src/Examples/OpenApiNSwagClientExample/OpenApiNSwagClientExample.csproj
index c30833a39a..079e43121c 100644
--- a/src/Examples/OpenApiNSwagClientExample/OpenApiNSwagClientExample.csproj
+++ b/src/Examples/OpenApiNSwagClientExample/OpenApiNSwagClientExample.csproj
@@ -1,7 +1,7 @@
- net9.0
+ net10.0
diff --git a/src/Examples/ReportsExample/ReportsExample.csproj b/src/Examples/ReportsExample/ReportsExample.csproj
index 6ade1386be..73a16ddf4f 100644
--- a/src/Examples/ReportsExample/ReportsExample.csproj
+++ b/src/Examples/ReportsExample/ReportsExample.csproj
@@ -1,6 +1,6 @@
- net9.0;net8.0
+ net10.0;net9.0;net8.0
diff --git a/src/JsonApiDotNetCore.Annotations/JsonApiDotNetCore.Annotations.csproj b/src/JsonApiDotNetCore.Annotations/JsonApiDotNetCore.Annotations.csproj
index ed36e0797c..68bd9ac569 100644
--- a/src/JsonApiDotNetCore.Annotations/JsonApiDotNetCore.Annotations.csproj
+++ b/src/JsonApiDotNetCore.Annotations/JsonApiDotNetCore.Annotations.csproj
@@ -1,6 +1,6 @@
- net8.0;netstandard1.0
+ net10.0;net8.0;netstandard1.0
true
true
JsonApiDotNetCore
diff --git a/src/JsonApiDotNetCore.OpenApi.Client.Kiota/JsonApiDotNetCore.OpenApi.Client.Kiota.csproj b/src/JsonApiDotNetCore.OpenApi.Client.Kiota/JsonApiDotNetCore.OpenApi.Client.Kiota.csproj
index 640b949477..fce1fb7c40 100644
--- a/src/JsonApiDotNetCore.OpenApi.Client.Kiota/JsonApiDotNetCore.OpenApi.Client.Kiota.csproj
+++ b/src/JsonApiDotNetCore.OpenApi.Client.Kiota/JsonApiDotNetCore.OpenApi.Client.Kiota.csproj
@@ -1,6 +1,6 @@
- net8.0
+ net10.0;net8.0
true
true
false
diff --git a/src/JsonApiDotNetCore.OpenApi.Client.NSwag/JsonApiDotNetCore.OpenApi.Client.NSwag.csproj b/src/JsonApiDotNetCore.OpenApi.Client.NSwag/JsonApiDotNetCore.OpenApi.Client.NSwag.csproj
index 20e2306730..550f284509 100644
--- a/src/JsonApiDotNetCore.OpenApi.Client.NSwag/JsonApiDotNetCore.OpenApi.Client.NSwag.csproj
+++ b/src/JsonApiDotNetCore.OpenApi.Client.NSwag/JsonApiDotNetCore.OpenApi.Client.NSwag.csproj
@@ -1,6 +1,6 @@
- net8.0
+ net10.0;net8.0
true
true
false
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ConfigureSwaggerGenOptions.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ConfigureSwaggerGenOptions.cs
index f3fb5198ca..200aa29ac7 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ConfigureSwaggerGenOptions.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ConfigureSwaggerGenOptions.cs
@@ -74,6 +74,8 @@ public void Configure(SwaggerGenOptions options)
options.DocumentFilter();
options.DocumentFilter();
options.DocumentFilter();
+ options.DocumentFilter();
+ options.DocumentFilter();
}
private List SelectDerivedTypes(Type baseType)
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiDotNetCore.OpenApi.Swashbuckle.csproj b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiDotNetCore.OpenApi.Swashbuckle.csproj
index 4a57ca1c85..b8be841a34 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiDotNetCore.OpenApi.Swashbuckle.csproj
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiDotNetCore.OpenApi.Swashbuckle.csproj
@@ -1,6 +1,6 @@
- net8.0
+ net10.0
true
true
false
@@ -33,6 +33,7 @@
+
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaIdSelector.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaIdSelector.cs
index 0e2fc803de..fc0cec1974 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaIdSelector.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaIdSelector.cs
@@ -120,7 +120,7 @@ public string GetSchemaId(Type type)
private string ApplySchemaTemplate(string schemaTemplate, ResourceType? resourceType, string? relationshipName, AtomicOperationCode? operationCode)
{
- string schemaId = schemaTemplate;
+ string? schemaId = schemaTemplate;
schemaId = resourceType != null
? schemaId.Replace("[ResourceName]", resourceType.PublicName.Singularize()).Pascalize()
@@ -136,7 +136,7 @@ private string ApplySchemaTemplate(string schemaTemplate, ResourceType? resource
schemaId = schemaId.Replace("[OperationCode]", operationCode.Value.ToString().Pascalize());
}
- string pascalCaseSchemaId = schemaId.Pascalize();
+ string? pascalCaseSchemaId = schemaId.Pascalize();
JsonNamingPolicy? namingPolicy = _options.SerializerOptions.PropertyNamingPolicy;
return namingPolicy != null ? namingPolicy.ConvertName(pascalCaseSchemaId) : pascalCaseSchemaId;
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/MicrosoftOpenApiCompatibilityExtensions.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/MicrosoftOpenApiCompatibilityExtensions.cs
new file mode 100644
index 0000000000..176d5cba82
--- /dev/null
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/MicrosoftOpenApiCompatibilityExtensions.cs
@@ -0,0 +1,24 @@
+using Microsoft.OpenApi.Models;
+
+namespace JsonApiDotNetCore.OpenApi.Swashbuckle;
+
+internal static class MicrosoftOpenApiCompatibilityExtensions
+{
+ public static void SetNullable(this OpenApiSchema schema, bool nullable)
+ {
+ ArgumentNullException.ThrowIfNull(schema);
+
+ if (nullable)
+ {
+ schema.Type ??= JsonSchemaType.Null;
+ schema.Type |= JsonSchemaType.Null;
+ }
+ else
+ {
+ if (schema.Type != null)
+ {
+ schema.Type &= ~JsonSchemaType.Null;
+ }
+ }
+ }
+}
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiDescriptionLinkProvider.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiDescriptionLinkProvider.cs
index 278c2154a9..2638711d1c 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiDescriptionLinkProvider.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiDescriptionLinkProvider.cs
@@ -30,7 +30,7 @@ public OpenApiDescriptionLinkProvider(IOptionsMonitor s
if (swaggerGeneratorOptions.SwaggerDocs.Count > 0)
{
- string latestVersionDocumentName = swaggerGeneratorOptions.SwaggerDocs.Last().Key;
+ string? latestVersionDocumentName = swaggerGeneratorOptions.SwaggerDocs.Last().Key;
SwaggerOptions swaggerOptions = _swaggerOptionsMonitor.CurrentValue;
return swaggerOptions.RouteTemplate.Replace("{documentName}", latestVersionDocumentName).Replace("{extension:regex(^(json|ya?ml)$)}", "json");
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiOperationIdSelector.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiOperationIdSelector.cs
index ed11481e27..550b8b599b 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiOperationIdSelector.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiOperationIdSelector.cs
@@ -94,7 +94,7 @@ private string ApplyTemplate(string openApiOperationIdTemplate, ResourceType? re
// @formatter:wrap_chained_method_calls chop_always
// @formatter:wrap_before_first_method_call true
- string pascalCaseOpenApiOperationId = openApiOperationIdTemplate
+ string? pascalCaseOpenApiOperationId = openApiOperationIdTemplate
.Replace("[Method]", method)
.Replace("[PrimaryResourceName]", resourceType?.PublicName.Singularize())
.Replace("[RelationshipName]", relationshipName)
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiSchemaExtensions.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiSchemaExtensions.cs
index 10095834b2..78416f6f76 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiSchemaExtensions.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiSchemaExtensions.cs
@@ -1,4 +1,5 @@
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle;
@@ -9,22 +10,23 @@ public static void ReorderProperties(this OpenApiSchema fullSchema, IEnumerable<
ArgumentNullException.ThrowIfNull(fullSchema);
ArgumentNullException.ThrowIfNull(propertyNamesInOrder);
- var propertiesInOrder = new Dictionary();
+ var propertiesInOrder = new Dictionary();
foreach (string propertyName in propertyNamesInOrder)
{
- if (fullSchema.Properties.TryGetValue(propertyName, out OpenApiSchema? schema))
+ if (fullSchema.Properties != null && fullSchema.Properties.TryGetValue(propertyName, out IOpenApiSchema? schema))
{
propertiesInOrder.Add(propertyName, schema);
}
}
+ ConsistencyGuard.ThrowIf(fullSchema.Properties == null);
ConsistencyGuard.ThrowIf(fullSchema.Properties.Count != propertiesInOrder.Count);
fullSchema.Properties = propertiesInOrder;
}
- public static OpenApiSchema WrapInExtendedSchema(this OpenApiSchema source)
+ public static OpenApiSchema WrapInExtendedSchema(this IOpenApiSchema source)
{
ArgumentNullException.ThrowIfNull(source);
@@ -34,11 +36,11 @@ public static OpenApiSchema WrapInExtendedSchema(this OpenApiSchema source)
};
}
- public static OpenApiSchema UnwrapLastExtendedSchema(this OpenApiSchema source)
+ public static IOpenApiSchema UnwrapLastExtendedSchema(this IOpenApiSchema source)
{
ArgumentNullException.ThrowIfNull(source);
- if (source.AllOf is { Count: > 0 })
+ if (source is OpenApiSchema && source.AllOf is { Count: > 0 })
{
return source.AllOf.Last();
}
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/RemoveTagsFilter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/RemoveTagsFilter.cs
new file mode 100644
index 0000000000..e38f5e5730
--- /dev/null
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/RemoveTagsFilter.cs
@@ -0,0 +1,14 @@
+using JetBrains.Annotations;
+using Microsoft.OpenApi.Models;
+using Swashbuckle.AspNetCore.SwaggerGen;
+
+namespace JsonApiDotNetCore.OpenApi.Swashbuckle;
+
+[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
+internal sealed class RemoveTagsFilter : IDocumentFilter
+{
+ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
+ {
+ swaggerDoc.Tags?.Clear();
+ }
+}
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs
index 78a25da441..37bb42fe40 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs
@@ -1,6 +1,7 @@
using JsonApiDotNetCore.Serialization.Objects;
-using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
@@ -19,7 +20,7 @@ public AtomicOperationCodeSchemaGenerator(SchemaGenerationTracer schemaGeneratio
_schemaIdSelector = schemaIdSelector;
}
- public OpenApiSchema GenerateSchema(AtomicOperationCode operationCode, SchemaRepository schemaRepository)
+ public IOpenApiSchema GenerateSchema(AtomicOperationCode operationCode, SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(schemaRepository);
@@ -27,14 +28,7 @@ public OpenApiSchema GenerateSchema(AtomicOperationCode operationCode, SchemaRep
if (schemaRepository.Schemas.ContainsKey(schemaId))
{
- return new OpenApiSchema
- {
- Reference = new OpenApiReference
- {
- Id = schemaId,
- Type = ReferenceType.Schema
- }
- };
+ return new OpenApiSchemaReference(schemaId);
}
using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, operationCode);
@@ -43,11 +37,11 @@ public OpenApiSchema GenerateSchema(AtomicOperationCode operationCode, SchemaRep
var fullSchema = new OpenApiSchema
{
- Type = "string",
- Enum = [new OpenApiString(enumValue)]
+ Type = JsonSchemaType.String,
+ Enum = [enumValue]
};
- OpenApiSchema referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema);
+ OpenApiSchemaReference? referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema);
traceScope.TraceSucceeded(schemaId);
return referenceSchema;
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs
index c4b41dd0f5..15ac1e84f3 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs
@@ -2,7 +2,8 @@
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiObjects.ResourceObjects;
using JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents;
-using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
@@ -27,21 +28,21 @@ public DataContainerSchemaGenerator(SchemaGenerationTracer schemaGenerationTrace
_resourceGraph = resourceGraph;
}
- public OpenApiSchema GenerateSchemaForCommonResourceDataInResponse(SchemaRepository schemaRepository)
+ public OpenApiSchemaReference GenerateSchemaForCommonResourceDataInResponse(SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(schemaRepository);
return _dataSchemaGenerator.GenerateSchemaForCommonData(typeof(ResourceInResponse), schemaRepository);
}
- public OpenApiSchema GenerateSchema(Type dataContainerSchemaType, ResourceType resourceType, bool forRequestSchema, bool canIncludeRelated,
+ public IOpenApiSchema GenerateSchema(Type dataContainerSchemaType, ResourceType resourceType, bool forRequestSchema, bool canIncludeRelated,
SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(dataContainerSchemaType);
ArgumentNullException.ThrowIfNull(resourceType);
ArgumentNullException.ThrowIfNull(schemaRepository);
- if (schemaRepository.TryLookupByType(dataContainerSchemaType, out OpenApiSchema referenceSchemaForData))
+ if (schemaRepository.TryLookupByType(dataContainerSchemaType, out OpenApiSchemaReference? referenceSchemaForData))
{
return referenceSchemaForData;
}
@@ -68,7 +69,7 @@ public OpenApiSchema GenerateSchema(Type dataContainerSchemaType, ResourceType r
}
referenceSchemaForData = _dataSchemaGenerator.GenerateSchema(dataConstructedType, forRequestSchema, schemaRepository);
- traceScope.TraceSucceeded(referenceSchemaForData.Reference.Id);
+ traceScope.TraceSucceeded(referenceSchemaForData.Reference.Id!);
return referenceSchemaForData;
}
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs
index 4d7783f780..dedf35e2f2 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs
@@ -1,12 +1,17 @@
using System.Collections.Concurrent;
using System.Reflection;
using System.Runtime.CompilerServices;
+using System.Text.Json;
+using System.Text.Json.Nodes;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiMetadata;
using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiObjects.ResourceObjects;
using JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents;
-using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Extensions;
+using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
@@ -79,7 +84,7 @@ public DataSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, Schema
_resourceDocumentationReader = resourceDocumentationReader;
}
- public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema, SchemaRepository schemaRepository)
+ public OpenApiSchemaReference GenerateSchema(Type dataSchemaType, bool forRequestSchema, SchemaRepository schemaRepository)
{
// For a given resource (identifier) type, we always generate the full type hierarchy. Discriminator mappings
// are managed manually, because there's no way to intercept in the Swashbuckle recursive component schema generation.
@@ -87,7 +92,7 @@ public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema,
ArgumentNullException.ThrowIfNull(dataSchemaType);
ArgumentNullException.ThrowIfNull(schemaRepository);
- if (schemaRepository.TryLookupByType(dataSchemaType, out OpenApiSchema referenceSchemaForData))
+ if (schemaRepository.TryLookupByType(dataSchemaType, out OpenApiSchemaReference? referenceSchemaForData))
{
return referenceSchemaForData;
}
@@ -114,11 +119,11 @@ public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema,
using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, dataSchemaType);
- referenceSchemaForData = _defaultSchemaGenerator.GenerateSchema(dataSchemaType, schemaRepository);
- OpenApiSchema fullSchemaForData = schemaRepository.Schemas[referenceSchemaForData.Reference.Id];
+ referenceSchemaForData = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(dataSchemaType, schemaRepository);
+ var fullSchemaForData = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForData.Reference.Id!];
fullSchemaForData.AdditionalPropertiesAllowed = false;
- OpenApiSchema inlineSchemaForData = fullSchemaForData.UnwrapLastExtendedSchema();
+ var inlineSchemaForData = (OpenApiSchema)fullSchemaForData.UnwrapLastExtendedSchema();
SetAbstract(inlineSchemaForData, resourceSchemaType);
SetResourceType(inlineSchemaForData, resourceType, schemaRepository);
@@ -142,10 +147,11 @@ public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema,
if (RequiresRootObjectTypeInDataSchema(resourceSchemaType, forRequestSchema))
{
- fullSchemaForData.Extensions[SetSchemaTypeToObjectDocumentFilter.RequiresRootObjectTypeKey] = new OpenApiBoolean(true);
+ fullSchemaForData.Extensions ??= new Dictionary();
+ fullSchemaForData.Extensions[SetSchemaTypeToObjectDocumentFilter.RequiresRootObjectTypeKey] = new JsonNodeExtension(true);
}
- traceScope.TraceSucceeded(referenceSchemaForData.Reference.Id);
+ traceScope.TraceSucceeded(referenceSchemaForData.Reference.Id!);
return referenceSchemaForData;
}
@@ -202,39 +208,39 @@ public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema,
return boxedSchemaType.Value;
}
- public OpenApiSchema GenerateSchemaForCommonData(Type commonDataSchemaType, SchemaRepository schemaRepository)
+ public OpenApiSchemaReference GenerateSchemaForCommonData(Type commonDataSchemaType, SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(commonDataSchemaType);
ArgumentNullException.ThrowIfNull(schemaRepository);
- if (schemaRepository.TryLookupByType(commonDataSchemaType, out OpenApiSchema? referenceSchema))
+ if (schemaRepository.TryLookupByType(commonDataSchemaType, out OpenApiSchemaReference? referenceSchema))
{
return referenceSchema;
}
using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, commonDataSchemaType);
- OpenApiSchema referenceSchemaForResourceType = _resourceTypeSchemaGenerator.GenerateSchema(schemaRepository);
- OpenApiSchema referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository);
+ OpenApiSchemaReference referenceSchemaForResourceType = _resourceTypeSchemaGenerator.GenerateSchema(schemaRepository);
+ OpenApiSchemaReference referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository);
var fullSchema = new OpenApiSchema
{
- Type = "object",
- Required = new SortedSet([JsonApiPropertyName.Type]),
- Properties = new Dictionary
+ Type = JsonSchemaType.Object,
+ Required = [JsonApiPropertyName.Type],
+ Properties = new Dictionary
{
[JsonApiPropertyName.Type] = referenceSchemaForResourceType.WrapInExtendedSchema(),
- [referenceSchemaForMeta.Reference.Id] = referenceSchemaForMeta.WrapInExtendedSchema()
+ [referenceSchemaForMeta.Reference.Id!] = referenceSchemaForMeta.WrapInExtendedSchema()
},
AdditionalPropertiesAllowed = false,
Discriminator = new OpenApiDiscriminator
{
PropertyName = JsonApiPropertyName.Type,
- Mapping = new SortedDictionary(StringComparer.Ordinal)
+ Mapping = new Dictionary(StringComparer.Ordinal)
},
- Extensions =
+ Extensions = new Dictionary
{
- ["x-abstract"] = new OpenApiBoolean(true)
+ ["x-abstract"] = new JsonNodeExtension(true)
}
};
@@ -251,7 +257,7 @@ private static ResourceType GetUltimateBaseType(ResourceType resourceType)
{
return UltimateBaseResourceTypeCache.GetOrAdd(resourceType, type =>
{
- ResourceType baseType = type;
+ ResourceType? baseType = type;
while (baseType.BaseType != null)
{
@@ -272,15 +278,16 @@ private static void SetAbstract(OpenApiSchema fullSchema, ResourceSchemaType res
{
if (resourceSchemaType.ResourceType.ClrType.IsAbstract && resourceSchemaType.SchemaOpenType != typeof(IdentifierInRequest<>))
{
- fullSchema.Extensions["x-abstract"] = new OpenApiBoolean(true);
+ fullSchema.Extensions ??= new Dictionary();
+ fullSchema.Extensions["x-abstract"] = new JsonNodeExtension(true);
}
}
private void SetResourceType(OpenApiSchema fullSchema, ResourceType resourceType, SchemaRepository schemaRepository)
{
- if (fullSchema.Properties.ContainsKey(JsonApiPropertyName.Type))
+ if (fullSchema.Properties != null && fullSchema.Properties.ContainsKey(JsonApiPropertyName.Type))
{
- OpenApiSchema referenceSchema = _resourceTypeSchemaGenerator.GenerateSchema(resourceType, schemaRepository);
+ OpenApiSchemaReference referenceSchema = _resourceTypeSchemaGenerator.GenerateSchema(resourceType, schemaRepository);
fullSchema.Properties[JsonApiPropertyName.Type] = referenceSchema.WrapInExtendedSchema();
}
}
@@ -295,9 +302,12 @@ private void AdaptResourceIdentity(OpenApiSchema fullSchema, ResourceSchemaType
bool hasAtomicOperationsEndpoint = _generationCacheSchemaGenerator.HasAtomicOperationsEndpoint(schemaRepository);
+ Dictionary fullSchemaProperties = fullSchema.Properties!;
+ HashSet fullSchemaRequired = fullSchema.Required!;
+
if (!hasAtomicOperationsEndpoint)
{
- fullSchema.Properties.Remove(JsonApiPropertyName.Lid);
+ fullSchemaProperties.Remove(JsonApiPropertyName.Lid);
}
if (resourceSchemaType.SchemaOpenType == typeof(DataInCreateRequest<>))
@@ -308,23 +318,23 @@ private void AdaptResourceIdentity(OpenApiSchema fullSchema, ResourceSchemaType
{
if (clientIdGeneration == ClientIdGenerationMode.Forbidden)
{
- fullSchema.Properties.Remove(JsonApiPropertyName.Id);
+ fullSchemaProperties.Remove(JsonApiPropertyName.Id);
}
else if (clientIdGeneration == ClientIdGenerationMode.Required)
{
- fullSchema.Properties.Remove(JsonApiPropertyName.Lid);
- fullSchema.Required.Add(JsonApiPropertyName.Id);
+ fullSchemaProperties.Remove(JsonApiPropertyName.Lid);
+ fullSchemaRequired.Add(JsonApiPropertyName.Id);
}
}
else
{
if (clientIdGeneration == ClientIdGenerationMode.Forbidden)
{
- fullSchema.Properties.Remove(JsonApiPropertyName.Id);
+ fullSchemaProperties.Remove(JsonApiPropertyName.Id);
}
else if (clientIdGeneration == ClientIdGenerationMode.Required)
{
- fullSchema.Required.Add(JsonApiPropertyName.Id);
+ fullSchemaRequired.Add(JsonApiPropertyName.Id);
}
}
}
@@ -332,14 +342,14 @@ private void AdaptResourceIdentity(OpenApiSchema fullSchema, ResourceSchemaType
{
if (!hasAtomicOperationsEndpoint)
{
- fullSchema.Required.Add(JsonApiPropertyName.Id);
+ fullSchemaRequired.Add(JsonApiPropertyName.Id);
}
}
}
private void SetResourceId(OpenApiSchema fullSchema, ResourceType resourceType, SchemaRepository schemaRepository)
{
- if (fullSchema.Properties.ContainsKey(JsonApiPropertyName.Id))
+ if (fullSchema.Properties != null && fullSchema.Properties.ContainsKey(JsonApiPropertyName.Id))
{
OpenApiSchema idSchema = _resourceIdSchemaGenerator.GenerateSchema(resourceType, schemaRepository);
fullSchema.Properties[JsonApiPropertyName.Id] = idSchema;
@@ -349,7 +359,7 @@ private void SetResourceId(OpenApiSchema fullSchema, ResourceType resourceType,
private void SetResourceFields(OpenApiSchema fullSchemaForData, ResourceSchemaType resourceSchemaType, bool forRequestSchema,
SchemaRepository schemaRepository)
{
- bool schemaHasFields = fullSchemaForData.Properties.ContainsKey(JsonApiPropertyName.Attributes) &&
+ bool schemaHasFields = fullSchemaForData.Properties != null && fullSchemaForData.Properties.ContainsKey(JsonApiPropertyName.Attributes) &&
fullSchemaForData.Properties.ContainsKey(JsonApiPropertyName.Relationships);
if (schemaHasFields)
@@ -367,8 +377,8 @@ private void SetFieldSchemaMembers(OpenApiSchema fullSchemaForData, ResourceSche
{
string propertyNameInSchema = forAttributes ? JsonApiPropertyName.Attributes : JsonApiPropertyName.Relationships;
- OpenApiSchema referenceSchemaForFields = fullSchemaForData.Properties[propertyNameInSchema].UnwrapLastExtendedSchema();
- OpenApiSchema fullSchemaForFields = schemaRepository.Schemas[referenceSchemaForFields.Reference.Id];
+ var referenceSchemaForFields = (OpenApiSchemaReference)fullSchemaForData.Properties![propertyNameInSchema].UnwrapLastExtendedSchema();
+ var fullSchemaForFields = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForFields.Reference.Id!];
fullSchemaForFields.AdditionalPropertiesAllowed = false;
SetAbstract(fullSchemaForFields, resourceSchemaTypeForData);
@@ -382,10 +392,10 @@ private void SetFieldSchemaMembers(OpenApiSchema fullSchemaForData, ResourceSche
fieldSchemaBuilder.SetMembersOfRelationships(fullSchemaForFields, forRequestSchema, schemaRepository);
}
- if (fullSchemaForFields.Properties.Count == 0 && !resourceSchemaTypeForData.ResourceType.IsPartOfTypeHierarchy())
+ if (fullSchemaForFields.Properties is { Count: 0 } && !resourceSchemaTypeForData.ResourceType.IsPartOfTypeHierarchy())
{
fullSchemaForData.Properties.Remove(propertyNameInSchema);
- schemaRepository.Schemas.Remove(referenceSchemaForFields.Reference.Id);
+ schemaRepository.Schemas.Remove(referenceSchemaForFields.Reference.Id!);
}
else
{
@@ -414,9 +424,9 @@ private void SetFieldSchemaMembers(OpenApiSchema fullSchemaForData, ResourceSche
baseSchemaType = commonFieldsSchemaType;
}
- OpenApiSchema referenceSchemaForBase = schemaRepository.LookupByType(baseSchemaType);
+ OpenApiSchemaReference referenceSchemaForBase = schemaRepository.LookupByType(baseSchemaType);
- schemaRepository.Schemas[referenceSchemaForFields.Reference.Id] = new OpenApiSchema
+ schemaRepository.Schemas[referenceSchemaForFields.Reference.Id!] = new OpenApiSchema
{
AllOf =
[
@@ -437,22 +447,22 @@ private ResourceSchemaType GetResourceSchemaTypeForFieldsProperty(ResourceSchema
return ResourceSchemaType.Create(fieldsConstructedType, _resourceGraph);
}
- private OpenApiSchema GenerateSchemaForCommonFields(Type commonFieldsSchemaType, SchemaRepository schemaRepository)
+ private OpenApiSchemaReference GenerateSchemaForCommonFields(Type commonFieldsSchemaType, SchemaRepository schemaRepository)
{
- if (schemaRepository.TryLookupByType(commonFieldsSchemaType, out OpenApiSchema? referenceSchema))
+ if (schemaRepository.TryLookupByType(commonFieldsSchemaType, out OpenApiSchemaReference? referenceSchema))
{
return referenceSchema;
}
using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, commonFieldsSchemaType);
- OpenApiSchema referenceSchemaForResourceType = _resourceTypeSchemaGenerator.GenerateSchema(schemaRepository);
+ OpenApiSchemaReference referenceSchemaForResourceType = _resourceTypeSchemaGenerator.GenerateSchema(schemaRepository);
var fullSchema = new OpenApiSchema
{
- Type = "object",
- Required = new SortedSet([OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName]),
- Properties = new Dictionary
+ Type = JsonSchemaType.Object,
+ Required = [OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName],
+ Properties = new Dictionary
{
[OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName] = referenceSchemaForResourceType.WrapInExtendedSchema()
},
@@ -460,11 +470,11 @@ private OpenApiSchema GenerateSchemaForCommonFields(Type commonFieldsSchemaType,
Discriminator = new OpenApiDiscriminator
{
PropertyName = OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName,
- Mapping = new SortedDictionary(StringComparer.Ordinal)
+ Mapping = new Dictionary(StringComparer.Ordinal)
},
- Extensions =
+ Extensions = new Dictionary
{
- ["x-abstract"] = new OpenApiBoolean(true)
+ ["x-abstract"] = new JsonNodeExtension(true)
}
};
@@ -480,7 +490,7 @@ private OpenApiSchema GenerateSchemaForCommonFields(Type commonFieldsSchemaType,
private void MapInDiscriminator(ResourceSchemaType resourceSchemaType, bool forRequestSchema, string discriminatorPropertyName,
SchemaRepository schemaRepository)
{
- OpenApiSchema referenceSchemaForDerived = schemaRepository.LookupByType(resourceSchemaType.SchemaConstructedType);
+ OpenApiSchemaReference referenceSchemaForDerived = schemaRepository.LookupByType(resourceSchemaType.SchemaConstructedType);
foreach (ResourceType? baseResourceType in GetBaseTypesToMapInto(resourceSchemaType, forRequestSchema))
{
@@ -488,23 +498,25 @@ private void MapInDiscriminator(ResourceSchemaType resourceSchemaType, bool forR
? GetCommonSchemaType(resourceSchemaType.SchemaOpenType)!
: resourceSchemaType.ChangeResourceType(baseResourceType).SchemaConstructedType;
- OpenApiSchema referenceSchemaForBase = schemaRepository.LookupByType(baseSchemaType);
- OpenApiSchema inlineSchemaForBase = schemaRepository.Schemas[referenceSchemaForBase.Reference.Id].UnwrapLastExtendedSchema();
+ OpenApiSchemaReference referenceSchemaForBase = schemaRepository.LookupByType(baseSchemaType);
+ var inlineSchemaForBase = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForBase.Reference.Id!].UnwrapLastExtendedSchema();
inlineSchemaForBase.Discriminator ??= new OpenApiDiscriminator
{
PropertyName = discriminatorPropertyName,
- Mapping = new SortedDictionary(StringComparer.Ordinal)
+ Mapping = new Dictionary(StringComparer.Ordinal)
};
if (RepeatDiscriminatorInResponseDerivedTypes && !forRequestSchema)
{
+ inlineSchemaForBase.Required ??= [];
inlineSchemaForBase.Required.Add(discriminatorPropertyName);
}
string publicName = resourceSchemaType.ResourceType.PublicName;
+ inlineSchemaForBase.Discriminator.Mapping ??= [];
- if (inlineSchemaForBase.Discriminator.Mapping.TryAdd(publicName, referenceSchemaForDerived.Reference.ReferenceV3) && baseResourceType == null)
+ if (inlineSchemaForBase.Discriminator.Mapping.TryAdd(publicName, referenceSchemaForDerived) && baseResourceType == null)
{
MapResourceTypeInEnum(publicName, schemaRepository);
}
@@ -543,11 +555,13 @@ private void MapInDiscriminator(ResourceSchemaType resourceSchemaType, bool forR
private void MapResourceTypeInEnum(string publicName, SchemaRepository schemaRepository)
{
string schemaId = _schemaIdSelector.GetResourceTypeSchemaId(null);
- OpenApiSchema fullSchema = schemaRepository.Schemas[schemaId];
+ var fullSchema = (OpenApiSchema)schemaRepository.Schemas[schemaId];
+ fullSchema.Enum ??= [];
- if (!fullSchema.Enum.Any(openApiAny => openApiAny is OpenApiString openApiString && openApiString.Value == publicName))
+ if (!fullSchema.Enum.Any(openApiAny => openApiAny is JsonValue openApiString && openApiString.GetValueKind() == JsonValueKind.String &&
+ openApiString.GetValue() == publicName))
{
- fullSchema.Enum.Add(new OpenApiString(publicName));
+ fullSchema.Enum.Add(publicName);
}
}
@@ -563,7 +577,7 @@ private void SetLinksVisibility(OpenApiSchema fullSchema, ResourceSchemaType res
private void GenerateDataSchemasForDirectlyDerivedTypes(ResourceSchemaType resourceSchemaType, bool forRequestSchema, SchemaRepository schemaRepository)
{
- OpenApiSchema referenceSchemaForBase = schemaRepository.LookupByType(resourceSchemaType.SchemaConstructedType);
+ OpenApiSchemaReference referenceSchemaForBase = schemaRepository.LookupByType(resourceSchemaType.SchemaConstructedType);
foreach (ResourceType derivedType in resourceSchemaType.ResourceType.DirectlyDerivedTypes)
{
@@ -572,18 +586,18 @@ private void GenerateDataSchemasForDirectlyDerivedTypes(ResourceSchemaType resou
using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, resourceSchemaTypeForDerived.SchemaConstructedType);
- OpenApiSchema referenceSchemaForDerived = _defaultSchemaGenerator.GenerateSchema(derivedSchemaType, schemaRepository);
- OpenApiSchema fullSchemaForDerived = schemaRepository.Schemas[referenceSchemaForDerived.Reference.Id];
+ var referenceSchemaForDerived = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(derivedSchemaType, schemaRepository);
+ var fullSchemaForDerived = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForDerived.Reference.Id!];
fullSchemaForDerived.AdditionalPropertiesAllowed = false;
- OpenApiSchema inlineSchemaForDerived = fullSchemaForDerived.UnwrapLastExtendedSchema();
+ var inlineSchemaForDerived = (OpenApiSchema)fullSchemaForDerived.UnwrapLastExtendedSchema();
SetResourceFields(inlineSchemaForDerived, resourceSchemaTypeForDerived, forRequestSchema, schemaRepository);
SetAbstract(inlineSchemaForDerived, resourceSchemaTypeForDerived);
RemoveProperties(inlineSchemaForDerived);
MapInDiscriminator(resourceSchemaTypeForDerived, forRequestSchema, JsonApiPropertyName.Type, schemaRepository);
- if (fullSchemaForDerived.AllOf.Count == 0)
+ if (fullSchemaForDerived.AllOf == null || fullSchemaForDerived.AllOf.Count == 0)
{
var compositeSchemaForDerived = new OpenApiSchema
{
@@ -595,7 +609,7 @@ private void GenerateDataSchemasForDirectlyDerivedTypes(ResourceSchemaType resou
AdditionalPropertiesAllowed = false
};
- schemaRepository.Schemas[referenceSchemaForDerived.Reference.Id] = compositeSchemaForDerived;
+ schemaRepository.Schemas[referenceSchemaForDerived.Reference.Id!] = compositeSchemaForDerived;
}
else
{
@@ -604,22 +618,26 @@ private void GenerateDataSchemasForDirectlyDerivedTypes(ResourceSchemaType resou
if (RequiresRootObjectTypeInDataSchema(resourceSchemaTypeForDerived, forRequestSchema))
{
- OpenApiSchema fullSchemaForData = schemaRepository.Schemas[referenceSchemaForDerived.Reference.Id];
- fullSchemaForData.Extensions[SetSchemaTypeToObjectDocumentFilter.RequiresRootObjectTypeKey] = new OpenApiBoolean(true);
+ var fullSchemaForData = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForDerived.Reference.Id!];
+ fullSchemaForData.Extensions ??= new Dictionary();
+ fullSchemaForData.Extensions[SetSchemaTypeToObjectDocumentFilter.RequiresRootObjectTypeKey] = new JsonNodeExtension(true);
}
GenerateDataSchemasForDirectlyDerivedTypes(resourceSchemaTypeForDerived, forRequestSchema, schemaRepository);
- traceScope.TraceSucceeded(referenceSchemaForDerived.Reference.Id);
+ traceScope.TraceSucceeded(referenceSchemaForDerived.Reference.Id!);
}
}
private static void RemoveProperties(OpenApiSchema fullSchema)
{
- foreach (string propertyName in fullSchema.Properties.Keys)
+ if (fullSchema.Properties != null)
{
- fullSchema.Properties.Remove(propertyName);
- fullSchema.Required.Remove(propertyName);
+ foreach (string propertyName in fullSchema.Properties.Keys)
+ {
+ fullSchema.Properties.Remove(propertyName);
+ fullSchema.Required?.Remove(propertyName);
+ }
}
}
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/LinksVisibilitySchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/LinksVisibilitySchemaGenerator.cs
index 5c099a3fc1..d7c87dd316 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/LinksVisibilitySchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/LinksVisibilitySchemaGenerator.cs
@@ -5,6 +5,8 @@
using JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents;
using JsonApiDotNetCore.Resources.Annotations;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
@@ -110,32 +112,32 @@ public void UpdateSchemaForRelationship(Type schemaType, OpenApiSchema fullSchem
private void UpdateLinksProperty(OpenApiSchema fullSchemaForLinksContainer, LinkTypes visibleLinkTypes, LinkTypes possibleLinkTypes,
SchemaRepository schemaRepository)
{
- OpenApiSchema referenceSchemaForLinks = fullSchemaForLinksContainer.Properties[JsonApiPropertyName.Links].UnwrapLastExtendedSchema();
+ var referenceSchemaForLinks = (OpenApiSchemaReference)fullSchemaForLinksContainer.Properties![JsonApiPropertyName.Links].UnwrapLastExtendedSchema();
if ((visibleLinkTypes & possibleLinkTypes) == 0)
{
- fullSchemaForLinksContainer.Required.Remove(JsonApiPropertyName.Links);
+ fullSchemaForLinksContainer.Required?.Remove(JsonApiPropertyName.Links);
fullSchemaForLinksContainer.Properties.Remove(JsonApiPropertyName.Links);
- schemaRepository.Schemas.Remove(referenceSchemaForLinks.Reference.Id);
+ schemaRepository.Schemas.Remove(referenceSchemaForLinks.Reference.Id!);
}
else if (visibleLinkTypes != possibleLinkTypes)
{
- string linksSchemaId = referenceSchemaForLinks.Reference.Id;
+ string linksSchemaId = referenceSchemaForLinks.Reference.Id!;
- if (schemaRepository.Schemas.TryGetValue(linksSchemaId, out OpenApiSchema? fullSchemaForLinks))
+ if (schemaRepository.Schemas.TryGetValue(linksSchemaId, out IOpenApiSchema? fullSchemaForLinks))
{
UpdateLinkProperties(fullSchemaForLinks, visibleLinkTypes);
}
}
}
- private void UpdateLinkProperties(OpenApiSchema fullSchemaForLinks, LinkTypes availableLinkTypes)
+ private void UpdateLinkProperties(IOpenApiSchema fullSchemaForLinks, LinkTypes availableLinkTypes)
{
foreach (string propertyName in LinkTypeToPropertyNamesMap.Where(pair => !availableLinkTypes.HasFlag(pair.Key)).SelectMany(pair => pair.Value))
{
- fullSchemaForLinks.Required.Remove(propertyName);
- fullSchemaForLinks.Properties.Remove(propertyName);
+ fullSchemaForLinks.Required?.Remove(propertyName);
+ fullSchemaForLinks.Properties?.Remove(propertyName);
}
}
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs
index 1e1bd07852..f33a95c084 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs
@@ -1,5 +1,6 @@
using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiObjects;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
@@ -19,11 +20,11 @@ public MetaSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, JsonAp
_schemaIdSelector = schemaIdSelector;
}
- public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository)
+ public OpenApiSchemaReference GenerateSchema(SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(schemaRepository);
- if (schemaRepository.TryLookupByType(SchemaType, out OpenApiSchema? referenceSchema))
+ if (schemaRepository.TryLookupByType(SchemaType, out OpenApiSchemaReference? referenceSchema))
{
return referenceSchema;
}
@@ -32,10 +33,10 @@ public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository)
var fullSchema = new OpenApiSchema
{
- Type = "object",
+ Type = JsonSchemaType.Object,
AdditionalProperties = new OpenApiSchema
{
- Nullable = true
+ Type = JsonSchemaType.Null
}
};
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs
index 98f176e8df..be9d64c37b 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs
@@ -2,6 +2,7 @@
using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiObjects.ResourceObjects;
using JsonApiDotNetCore.Resources.Annotations;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
@@ -34,7 +35,7 @@ public RelationshipIdentifierSchemaGenerator(SchemaGenerationTracer schemaGenera
_schemaIdSelector = schemaIdSelector;
}
- public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRepository schemaRepository)
+ public OpenApiSchemaReference GenerateSchema(RelationshipAttribute relationship, SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(relationship);
ArgumentNullException.ThrowIfNull(schemaRepository);
@@ -43,14 +44,7 @@ public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRe
if (schemaRepository.Schemas.ContainsKey(schemaId))
{
- return new OpenApiSchema
- {
- Reference = new OpenApiReference
- {
- Id = schemaId,
- Type = ReferenceType.Schema
- }
- };
+ return new OpenApiSchemaReference(schemaId);
}
using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, relationship);
@@ -58,17 +52,19 @@ public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRe
Type relationshipIdentifierConstructedType = typeof(RelationshipIdentifier<>).MakeGenericType(relationship.LeftType.ClrType);
ConsistencyGuard.ThrowIf(schemaRepository.TryLookupByType(relationshipIdentifierConstructedType, out _));
- OpenApiSchema referenceSchemaForIdentifier = _defaultSchemaGenerator.GenerateSchema(relationshipIdentifierConstructedType, schemaRepository);
- OpenApiSchema fullSchemaForIdentifier = schemaRepository.Schemas[referenceSchemaForIdentifier.Reference.Id];
+ var referenceSchemaForIdentifier =
+ (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(relationshipIdentifierConstructedType, schemaRepository);
- fullSchemaForIdentifier.Properties.Remove(JsonApiPropertyName.Meta);
+ var fullSchemaForIdentifier = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForIdentifier.Reference.Id!];
+
+ fullSchemaForIdentifier.Properties?.Remove(JsonApiPropertyName.Meta);
SetResourceType(fullSchemaForIdentifier, relationship.LeftType, schemaRepository);
SetResourceId(fullSchemaForIdentifier, relationship.LeftType, schemaRepository);
SetRelationship(fullSchemaForIdentifier, relationship, schemaRepository);
schemaRepository.ReplaceSchemaId(relationshipIdentifierConstructedType, schemaId);
- referenceSchemaForIdentifier.Reference.Id = schemaId;
+ referenceSchemaForIdentifier = new OpenApiSchemaReference(schemaId);
traceScope.TraceSucceeded(schemaId);
return referenceSchemaForIdentifier;
@@ -76,19 +72,22 @@ public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRe
private void SetResourceType(OpenApiSchema fullSchemaForIdentifier, ResourceType resourceType, SchemaRepository schemaRepository)
{
- OpenApiSchema referenceSchema = _resourceTypeSchemaGenerator.GenerateSchema(resourceType, schemaRepository);
+ OpenApiSchemaReference referenceSchema = _resourceTypeSchemaGenerator.GenerateSchema(resourceType, schemaRepository);
+ fullSchemaForIdentifier.Properties ??= [];
fullSchemaForIdentifier.Properties[JsonApiPropertyName.Type] = referenceSchema.WrapInExtendedSchema();
}
private void SetResourceId(OpenApiSchema fullSchemaForResourceData, ResourceType resourceType, SchemaRepository schemaRepository)
{
OpenApiSchema idSchema = _resourceIdSchemaGenerator.GenerateSchema(resourceType, schemaRepository);
+ fullSchemaForResourceData.Properties ??= [];
fullSchemaForResourceData.Properties[JsonApiPropertyName.Id] = idSchema;
}
private void SetRelationship(OpenApiSchema fullSchemaForIdentifier, RelationshipAttribute relationship, SchemaRepository schemaRepository)
{
- OpenApiSchema referenceSchema = _relationshipNameSchemaGenerator.GenerateSchema(relationship, schemaRepository);
+ OpenApiSchemaReference referenceSchema = _relationshipNameSchemaGenerator.GenerateSchema(relationship, schemaRepository);
+ fullSchemaForIdentifier.Properties ??= [];
fullSchemaForIdentifier.Properties[JsonApiPropertyName.Relationship] = referenceSchema.WrapInExtendedSchema();
}
}
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs
index 7f5c0c5d3a..06f92571b6 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs
@@ -1,6 +1,6 @@
using JsonApiDotNetCore.Resources.Annotations;
-using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
@@ -19,7 +19,7 @@ public RelationshipNameSchemaGenerator(SchemaGenerationTracer schemaGenerationTr
_schemaIdSelector = schemaIdSelector;
}
- public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRepository schemaRepository)
+ public OpenApiSchemaReference GenerateSchema(RelationshipAttribute relationship, SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(relationship);
ArgumentNullException.ThrowIfNull(schemaRepository);
@@ -28,25 +28,18 @@ public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRe
if (schemaRepository.Schemas.ContainsKey(schemaId))
{
- return new OpenApiSchema
- {
- Reference = new OpenApiReference
- {
- Id = schemaId,
- Type = ReferenceType.Schema
- }
- };
+ return new OpenApiSchemaReference(schemaId);
}
using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, relationship);
var fullSchema = new OpenApiSchema
{
- Type = "string",
- Enum = [new OpenApiString(relationship.PublicName)]
+ Type = JsonSchemaType.String,
+ Enum = [relationship.PublicName]
};
- OpenApiSchema referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema);
+ OpenApiSchemaReference? referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema);
traceScope.TraceSucceeded(schemaId);
return referenceSchema;
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs
index 21bc5020ed..d749770df6 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs
@@ -27,10 +27,10 @@ public OpenApiSchema GenerateSchema(Type resourceIdClrType, SchemaRepository sch
ArgumentNullException.ThrowIfNull(resourceIdClrType);
ArgumentNullException.ThrowIfNull(schemaRepository);
- OpenApiSchema idSchema = _defaultSchemaGenerator.GenerateSchema(resourceIdClrType, schemaRepository);
- ConsistencyGuard.ThrowIf(idSchema.Reference != null);
+ var idSchema = _defaultSchemaGenerator.GenerateSchema(resourceIdClrType, schemaRepository) as OpenApiSchema;
+ ConsistencyGuard.ThrowIf(idSchema == null);
- idSchema.Type = "string";
+ idSchema.Type = JsonSchemaType.String;
if (resourceIdClrType != typeof(string))
{
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs
index eb933bedbe..c52acb7acc 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs
@@ -1,7 +1,9 @@
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents;
-using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Extensions;
+using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
@@ -20,12 +22,12 @@ public ResourceTypeSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer
_schemaIdSelector = schemaIdSelector;
}
- public OpenApiSchema GenerateSchema(ResourceType resourceType, SchemaRepository schemaRepository)
+ public OpenApiSchemaReference GenerateSchema(ResourceType resourceType, SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(resourceType);
ArgumentNullException.ThrowIfNull(schemaRepository);
- if (schemaRepository.TryLookupByType(resourceType.ClrType, out OpenApiSchema? referenceSchema))
+ if (schemaRepository.TryLookupByType(resourceType.ClrType, out OpenApiSchemaReference? referenceSchema))
{
return referenceSchema;
}
@@ -34,17 +36,17 @@ public OpenApiSchema GenerateSchema(ResourceType resourceType, SchemaRepository
var fullSchema = new OpenApiSchema
{
- Type = "string",
- Enum = resourceType.ClrType.IsAbstract ? [] : [new OpenApiString(resourceType.PublicName)],
- Extensions =
+ Type = JsonSchemaType.String,
+ Enum = resourceType.ClrType.IsAbstract ? [] : [resourceType.PublicName],
+ Extensions = new Dictionary
{
- [StringEnumOrderingFilter.RequiresSortKey] = new OpenApiBoolean(true)
+ [StringEnumOrderingFilter.RequiresSortKey] = new JsonNodeExtension(true)
}
};
foreach (ResourceType derivedType in resourceType.GetAllConcreteDerivedTypes())
{
- fullSchema.Enum.Add(new OpenApiString(derivedType.PublicName));
+ fullSchema.Enum.Add(derivedType.PublicName);
}
string schemaId = _schemaIdSelector.GetResourceTypeSchemaId(resourceType);
@@ -56,34 +58,27 @@ public OpenApiSchema GenerateSchema(ResourceType resourceType, SchemaRepository
return referenceSchema;
}
- public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository)
+ public OpenApiSchemaReference GenerateSchema(SchemaRepository schemaRepository)
{
string schemaId = _schemaIdSelector.GetResourceTypeSchemaId(null);
if (schemaRepository.Schemas.ContainsKey(schemaId))
{
- return new OpenApiSchema
- {
- Reference = new OpenApiReference
- {
- Id = schemaId,
- Type = ReferenceType.Schema
- }
- };
+ return new OpenApiSchemaReference(schemaId);
}
using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this);
var fullSchema = new OpenApiSchema
{
- Type = "string",
- Extensions =
+ Type = JsonSchemaType.String,
+ Extensions = new Dictionary
{
- [StringEnumOrderingFilter.RequiresSortKey] = new OpenApiBoolean(true)
+ [StringEnumOrderingFilter.RequiresSortKey] = new JsonNodeExtension(true)
}
};
- OpenApiSchema referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema);
+ OpenApiSchemaReference? referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema);
traceScope.TraceSucceeded(schemaId);
return referenceSchema;
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs
index f128f89299..b4b6a4c725 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs
@@ -7,8 +7,11 @@
using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
using JsonApiDotNetCore.Resources.Annotations;
using JsonApiDotNetCore.Serialization.Objects;
-using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Extensions;
+using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents;
@@ -68,7 +71,7 @@ public override bool CanGenerate(Type schemaType)
return schemaType == typeof(OperationsRequestDocument) || schemaType == typeof(OperationsResponseDocument);
}
- protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository)
+ protected override OpenApiSchemaReference GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(schemaType);
ArgumentNullException.ThrowIfNull(schemaRepository);
@@ -84,7 +87,7 @@ protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaR
GenerateSchemasForResponseDocument(schemaRepository);
}
- return _defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository);
+ return (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository);
}
private void GenerateSchemasForRequestDocument(SchemaRepository schemaRepository)
@@ -97,38 +100,38 @@ private void GenerateSchemasForRequestDocument(SchemaRepository schemaRepository
}
}
- private OpenApiSchema GenerateSchemaForAbstractOperation(SchemaRepository schemaRepository)
+ private OpenApiSchemaReference GenerateSchemaForAbstractOperation(SchemaRepository schemaRepository)
{
- if (schemaRepository.TryLookupByType(AtomicOperationAbstractType, out OpenApiSchema? referenceSchema))
+ if (schemaRepository.TryLookupByType(AtomicOperationAbstractType, out OpenApiSchemaReference? referenceSchema))
{
return referenceSchema;
}
using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, AtomicOperationAbstractType);
- OpenApiSchema referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository);
+ OpenApiSchemaReference referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository);
var fullSchema = new OpenApiSchema
{
- Type = "object",
- Required = new SortedSet([OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName]),
- Properties = new Dictionary
+ Type = JsonSchemaType.Object,
+ Required = [OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName],
+ Properties = new Dictionary
{
- [OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName] = new()
+ [OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName] = new OpenApiSchema
{
- Type = "string"
+ Type = JsonSchemaType.String
},
- [referenceSchemaForMeta.Reference.Id] = referenceSchemaForMeta.WrapInExtendedSchema()
+ [referenceSchemaForMeta.Reference.Id!] = referenceSchemaForMeta.WrapInExtendedSchema()
},
AdditionalPropertiesAllowed = false,
Discriminator = new OpenApiDiscriminator
{
PropertyName = OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName,
- Mapping = new SortedDictionary(StringComparer.Ordinal)
+ Mapping = new Dictionary(StringComparer.Ordinal)
},
- Extensions =
+ Extensions = new Dictionary
{
- ["x-abstract"] = new OpenApiBoolean(true)
+ ["x-abstract"] = new JsonNodeExtension(true)
}
};
@@ -188,17 +191,18 @@ private void GenerateSchemaForResourceOperation(Type operationOpenType, Resource
}
}
- OpenApiSchema referenceSchemaForOperation = _defaultSchemaGenerator.GenerateSchema(operationConstructedType, schemaRepository);
- OpenApiSchema fullSchemaForOperation = schemaRepository.Schemas[referenceSchemaForOperation.Reference.Id];
+ var referenceSchemaForOperation = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(operationConstructedType, schemaRepository);
+ var fullSchemaForOperation = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForOperation.Reference.Id!];
fullSchemaForOperation.AdditionalPropertiesAllowed = false;
- OpenApiSchema inlineSchemaForOperation = fullSchemaForOperation.UnwrapLastExtendedSchema();
+ var inlineSchemaForOperation = (OpenApiSchema)fullSchemaForOperation.UnwrapLastExtendedSchema();
if (needsEmptyDerivedSchema)
{
Type baseOperationSchemaType = ChangeResourceTypeInSchemaType(operationOpenType, resourceType.BaseType!);
- OpenApiSchema referenceSchemaForBaseOperation = schemaRepository.LookupByType(baseOperationSchemaType);
+ OpenApiSchemaReference referenceSchemaForBaseOperation = schemaRepository.LookupByType(baseOperationSchemaType);
RemoveProperties(inlineSchemaForOperation);
+ fullSchemaForOperation.AllOf ??= [];
fullSchemaForOperation.AllOf[0] = referenceSchemaForBaseOperation;
}
else
@@ -209,7 +213,7 @@ private void GenerateSchemaForResourceOperation(Type operationOpenType, Resource
string discriminatorValue = _schemaIdSelector.GetAtomicOperationDiscriminatorValue(operationCode, resourceType);
MapInDiscriminator(referenceSchemaForOperation, discriminatorValue, schemaRepository);
- traceScope.TraceSucceeded(referenceSchemaForOperation.Reference.Id);
+ traceScope.TraceSucceeded(referenceSchemaForOperation.Reference.Id!);
}
foreach (ResourceType derivedType in resourceType.DirectlyDerivedTypes)
@@ -251,24 +255,30 @@ private static Type ChangeResourceTypeInSchemaType(Type schemaOpenType, Resource
private static void RemoveProperties(OpenApiSchema fullSchema)
{
- foreach (string propertyName in fullSchema.Properties.Keys)
+ if (fullSchema.Properties != null)
{
- fullSchema.Properties.Remove(propertyName);
- fullSchema.Required.Remove(propertyName);
+ foreach (string propertyName in fullSchema.Properties.Keys)
+ {
+ fullSchema.Properties.Remove(propertyName);
+ fullSchema.Required?.Remove(propertyName);
+ }
}
}
private void SetOperationCode(OpenApiSchema fullSchema, AtomicOperationCode operationCode, SchemaRepository schemaRepository)
{
- OpenApiSchema referenceSchema = _atomicOperationCodeSchemaGenerator.GenerateSchema(operationCode, schemaRepository);
+ var referenceSchema = (OpenApiSchemaReference)_atomicOperationCodeSchemaGenerator.GenerateSchema(operationCode, schemaRepository);
+ fullSchema.Properties ??= [];
fullSchema.Properties[JsonApiPropertyName.Op] = referenceSchema.WrapInExtendedSchema();
}
- private static void MapInDiscriminator(OpenApiSchema referenceSchemaForOperation, string discriminatorValue, SchemaRepository schemaRepository)
+ private static void MapInDiscriminator(OpenApiSchemaReference referenceSchemaForOperation, string discriminatorValue, SchemaRepository schemaRepository)
{
- OpenApiSchema referenceSchemaForAbstractOperation = schemaRepository.LookupByType(AtomicOperationAbstractType);
- OpenApiSchema fullSchemaForAbstractOperation = schemaRepository.Schemas[referenceSchemaForAbstractOperation.Reference.Id];
- fullSchemaForAbstractOperation.Discriminator.Mapping.Add(discriminatorValue, referenceSchemaForOperation.Reference.ReferenceV3);
+ OpenApiSchemaReference referenceSchemaForAbstractOperation = schemaRepository.LookupByType(AtomicOperationAbstractType);
+ var fullSchemaForAbstractOperation = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForAbstractOperation.Reference.Id!];
+ fullSchemaForAbstractOperation.Discriminator ??= new OpenApiDiscriminator();
+ fullSchemaForAbstractOperation.Discriminator.Mapping ??= [];
+ fullSchemaForAbstractOperation.Discriminator.Mapping.Add(discriminatorValue, referenceSchemaForOperation);
}
private static HashSet GetRelationshipsInTypeHierarchy(ResourceType baseType)
@@ -315,7 +325,7 @@ private void GenerateSchemaForRelationshipOperation(Type operationOpenType, Rela
RelationshipAttribute? relationshipInAnyBaseResourceType = GetRelationshipEnabledInAnyBase(relationship, writeOperation);
- OpenApiSchema? referenceSchemaForRelationshipIdentifier;
+ OpenApiSchemaReference? referenceSchemaForRelationshipIdentifier;
if (relationshipInAnyBaseResourceType == null)
{
@@ -337,22 +347,24 @@ private void GenerateSchemaForRelationshipOperation(Type operationOpenType, Rela
// the relationship name because there's no runtime Type available for it.
string schemaId = _schemaIdSelector.GetRelationshipAtomicOperationSchemaId(relationship, operationCode);
- OpenApiSchema referenceSchemaForOperation = _defaultSchemaGenerator.GenerateSchema(operationConstructedType, schemaRepository);
- OpenApiSchema fullSchemaForOperation = schemaRepository.Schemas[referenceSchemaForOperation.Reference.Id];
+ var referenceSchemaForOperation = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(operationConstructedType, schemaRepository);
+ var fullSchemaForOperation = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForOperation.Reference.Id!];
fullSchemaForOperation.AdditionalPropertiesAllowed = false;
- OpenApiSchema inlineSchemaForOperation = fullSchemaForOperation.UnwrapLastExtendedSchema();
+ var inlineSchemaForOperation = (OpenApiSchema)fullSchemaForOperation.UnwrapLastExtendedSchema();
SetOperationCode(inlineSchemaForOperation, operationCode, schemaRepository);
if (referenceSchemaForRelationshipIdentifier != null)
{
+ inlineSchemaForOperation.Properties ??= [];
inlineSchemaForOperation.Properties[JsonApiPropertyName.Ref] = referenceSchemaForRelationshipIdentifier.WrapInExtendedSchema();
}
- inlineSchemaForOperation.Properties[JsonApiPropertyName.Data].Nullable = _resourceFieldValidationMetadataProvider.IsNullable(relationship);
+ bool isNullable = _resourceFieldValidationMetadataProvider.IsNullable(relationship);
+ ((OpenApiSchema)inlineSchemaForOperation.Properties![JsonApiPropertyName.Data]).SetNullable(isNullable);
schemaRepository.ReplaceSchemaId(operationConstructedType, schemaId);
- referenceSchemaForOperation.Reference.Id = schemaId;
+ referenceSchemaForOperation = new OpenApiSchemaReference(schemaId);
if (relationshipInAnyBaseResourceType != null)
{
@@ -361,14 +373,8 @@ private void GenerateSchemaForRelationshipOperation(Type operationOpenType, Rela
string baseRelationshipSchemaId = _schemaIdSelector.GetRelationshipAtomicOperationSchemaId(relationshipInAnyBaseResourceType, operationCode);
ConsistencyGuard.ThrowIf(!schemaRepository.Schemas.ContainsKey(baseRelationshipSchemaId));
- fullSchemaForOperation.AllOf[0] = new OpenApiSchema
- {
- Reference = new OpenApiReference
- {
- Id = baseRelationshipSchemaId,
- Type = ReferenceType.Schema
- }
- };
+ fullSchemaForOperation.AllOf ??= [];
+ fullSchemaForOperation.AllOf[0] = new OpenApiSchemaReference(baseRelationshipSchemaId);
}
string discriminatorValue = _schemaIdSelector.GetAtomicOperationDiscriminatorValue(operationCode, relationship);
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs
index 740b2fca43..1baca73aa6 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs
@@ -1,6 +1,8 @@
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents;
@@ -31,12 +33,12 @@ protected DocumentSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer,
public abstract bool CanGenerate(Type schemaType);
- public OpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepository)
+ public IOpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(schemaType);
ArgumentNullException.ThrowIfNull(schemaRepository);
- if (schemaRepository.TryLookupByType(schemaType, out OpenApiSchema? referenceSchema))
+ if (schemaRepository.TryLookupByType(schemaType, out OpenApiSchemaReference? referenceSchema))
{
return referenceSchema;
}
@@ -46,21 +48,21 @@ public OpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepo
_metaSchemaGenerator.GenerateSchema(schemaRepository);
referenceSchema = GenerateDocumentSchema(schemaType, schemaRepository);
- OpenApiSchema fullSchema = schemaRepository.Schemas[referenceSchema.Reference.Id];
+ var fullSchema = (OpenApiSchema)schemaRepository.Schemas[referenceSchema.Reference.Id!];
_linksVisibilitySchemaGenerator.UpdateSchemaForTopLevel(schemaType, fullSchema, schemaRepository);
SetJsonApiVersion(fullSchema, schemaRepository);
- traceScope.TraceSucceeded(referenceSchema.Reference.Id);
+ traceScope.TraceSucceeded(referenceSchema.Reference.Id!);
return referenceSchema;
}
- protected abstract OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository);
+ protected abstract OpenApiSchemaReference GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository);
private void SetJsonApiVersion(OpenApiSchema fullSchema, SchemaRepository schemaRepository)
{
- if (fullSchema.Properties.ContainsKey(JsonApiPropertyName.Jsonapi) && !_options.IncludeJsonApiVersion)
+ if (fullSchema.Properties != null && fullSchema.Properties.ContainsKey(JsonApiPropertyName.Jsonapi) && !_options.IncludeJsonApiVersion)
{
fullSchema.Properties.Remove(JsonApiPropertyName.Jsonapi);
schemaRepository.Schemas.Remove(JsonApiPropertyName.Jsonapi);
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs
index 3d305e889b..1783ba7b8d 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs
@@ -3,6 +3,7 @@
using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
using JsonApiDotNetCore.Serialization.Objects;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents;
@@ -34,27 +35,28 @@ public override bool CanGenerate(Type schemaType)
return schemaType == typeof(ErrorResponseDocument);
}
- protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository)
+ protected override OpenApiSchemaReference GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(schemaType);
ArgumentNullException.ThrowIfNull(schemaRepository);
- OpenApiSchema referenceSchemaForErrorObject = GenerateSchemaForErrorObject(schemaRepository);
- OpenApiSchema fullSchemaForErrorObject = schemaRepository.Schemas[referenceSchemaForErrorObject.Reference.Id];
+ OpenApiSchemaReference referenceSchemaForErrorObject = GenerateSchemaForErrorObject(schemaRepository);
+ var fullSchemaForErrorObject = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForErrorObject.Reference.Id!];
- OpenApiSchema referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository);
+ OpenApiSchemaReference referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository);
+ fullSchemaForErrorObject.Properties ??= [];
fullSchemaForErrorObject.Properties[JsonApiPropertyName.Meta] = referenceSchemaForMeta.WrapInExtendedSchema();
- return _defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository);
+ return (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository);
}
- private OpenApiSchema GenerateSchemaForErrorObject(SchemaRepository schemaRepository)
+ private OpenApiSchemaReference GenerateSchemaForErrorObject(SchemaRepository schemaRepository)
{
using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, ErrorObjectType);
- OpenApiSchema referenceSchema = _defaultSchemaGenerator.GenerateSchema(ErrorObjectType, schemaRepository);
+ var referenceSchema = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(ErrorObjectType, schemaRepository);
- traceScope.TraceSucceeded(referenceSchema.Reference.Id);
+ traceScope.TraceSucceeded(referenceSchema.Reference.Id!);
return referenceSchema;
}
}
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs
index 767f0d0143..a177be776e 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs
@@ -4,6 +4,7 @@
using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
using JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents;
@@ -57,7 +58,7 @@ public override bool CanGenerate(Type schemaType)
return RequestDocumentSchemaTypes.Contains(schemaOpenType) || ResponseDocumentSchemaTypes.Contains(schemaOpenType);
}
- protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository)
+ protected override OpenApiSchemaReference GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository)
{
ArgumentNullException.ThrowIfNull(schemaType);
ArgumentNullException.ThrowIfNull(schemaRepository);
@@ -67,12 +68,13 @@ protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaR
_ = _dataContainerSchemaGenerator.GenerateSchema(schemaType, resourceSchemaType.ResourceType, isRequestSchema, !isRequestSchema, schemaRepository);
- OpenApiSchema? referenceSchemaForDocument = _defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository);
- OpenApiSchema inlineSchemaForDocument = schemaRepository.Schemas[referenceSchemaForDocument.Reference.Id].UnwrapLastExtendedSchema();
+ var referenceSchemaForDocument = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository);
+ var inlineSchemaForDocument = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForDocument.Reference.Id!].UnwrapLastExtendedSchema();
if (JsonApiSchemaFacts.HasNullableDataProperty(resourceSchemaType.SchemaOpenType))
{
- inlineSchemaForDocument.Properties[JsonApiPropertyName.Data].Nullable = true;
+ inlineSchemaForDocument.Properties ??= [];
+ ((OpenApiSchema)inlineSchemaForDocument.Properties[JsonApiPropertyName.Data]).SetNullable(true);
}
return referenceSchemaForDocument;
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs
index beba632ebf..2bd2963fd9 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs
@@ -2,8 +2,8 @@
using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiMetadata;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
-using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators;
@@ -38,30 +38,29 @@ public bool HasAtomicOperationsEndpoint(SchemaRepository schemaRepository)
OpenApiSchema fullSchema = GenerateFullSchema(schemaRepository);
- var hasAtomicOperationsEndpoint = (OpenApiBoolean)fullSchema.Properties[HasAtomicOperationsEndpointPropertyName].Default;
- return hasAtomicOperationsEndpoint.Value;
+ return fullSchema.Properties != null && (bool)fullSchema.Properties[HasAtomicOperationsEndpointPropertyName].Default!;
}
private OpenApiSchema GenerateFullSchema(SchemaRepository schemaRepository)
{
- if (schemaRepository.Schemas.TryGetValue(SchemaId, out OpenApiSchema? fullSchema))
+ if (schemaRepository.Schemas.TryGetValue(SchemaId, out IOpenApiSchema? existingFullSchema))
{
- return fullSchema;
+ return (OpenApiSchema)existingFullSchema;
}
using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this);
bool hasAtomicOperationsEndpoint = EvaluateHasAtomicOperationsEndpoint();
- fullSchema = new OpenApiSchema
+ var fullSchema = new OpenApiSchema
{
- Type = "object",
- Properties = new Dictionary
+ Type = JsonSchemaType.Object,
+ Properties = new Dictionary
{
- [HasAtomicOperationsEndpointPropertyName] = new()
+ [HasAtomicOperationsEndpointPropertyName] = new OpenApiSchema
{
- Type = "boolean",
- Default = new OpenApiBoolean(hasAtomicOperationsEndpoint)
+ Type = JsonSchemaType.Boolean,
+ Default = hasAtomicOperationsEndpoint
}
}
};
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/JsonApiSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/JsonApiSchemaGenerator.cs
index 19d94eb48e..7d22a3b7e1 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/JsonApiSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/JsonApiSchemaGenerator.cs
@@ -3,7 +3,7 @@
using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components;
using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
-using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators;
@@ -22,7 +22,7 @@ public JsonApiSchemaGenerator(ResourceIdSchemaGenerator resourceIdSchemaGenerato
_documentSchemaGenerators = documentSchemaGenerators as DocumentSchemaGenerator[] ?? documentSchemaGenerators.ToArray();
}
- public OpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepository, MemberInfo? memberInfo = null, ParameterInfo? parameterInfo = null,
+ public IOpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepository, MemberInfo? memberInfo = null, ParameterInfo? parameterInfo = null,
ApiParameterRouteInfo? routeInfo = null)
{
ArgumentNullException.ThrowIfNull(schemaType);
@@ -34,7 +34,7 @@ public OpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepo
}
DocumentSchemaGenerator schemaGenerator = GetDocumentSchemaGenerator(schemaType);
- OpenApiSchema referenceSchema = schemaGenerator.GenerateSchema(schemaType, schemaRepository);
+ IOpenApiSchema referenceSchema = schemaGenerator.GenerateSchema(schemaType, schemaRepository);
if (memberInfo != null || parameterInfo != null)
{
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaRepositoryExtensions.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaRepositoryExtensions.cs
index 669c50b4e0..71a3c62135 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaRepositoryExtensions.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaRepositoryExtensions.cs
@@ -1,5 +1,6 @@
using System.Reflection;
-using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle;
@@ -28,12 +29,12 @@ private static FieldInfo GetReservedIdsField()
return field;
}
- public static OpenApiSchema LookupByType(this SchemaRepository schemaRepository, Type schemaType)
+ public static OpenApiSchemaReference LookupByType(this SchemaRepository schemaRepository, Type schemaType)
{
ArgumentNullException.ThrowIfNull(schemaRepository);
ArgumentNullException.ThrowIfNull(schemaType);
- if (!schemaRepository.TryLookupByType(schemaType, out OpenApiSchema? referenceSchema))
+ if (!schemaRepository.TryLookupByType(schemaType, out OpenApiSchemaReference? referenceSchema))
{
throw new InvalidOperationException($"Reference schema for '{schemaType.Name}' does not exist.");
}
@@ -47,11 +48,11 @@ public static void ReplaceSchemaId(this SchemaRepository schemaRepository, Type
ArgumentNullException.ThrowIfNull(oldSchemaType);
ArgumentException.ThrowIfNullOrEmpty(newSchemaId);
- if (schemaRepository.TryLookupByType(oldSchemaType, out OpenApiSchema? referenceSchema))
+ if (schemaRepository.TryLookupByType(oldSchemaType, out OpenApiSchemaReference? referenceSchema))
{
- string oldSchemaId = referenceSchema.Reference.Id;
+ string oldSchemaId = referenceSchema.Reference.Id!;
- OpenApiSchema fullSchema = schemaRepository.Schemas[oldSchemaId];
+ IOpenApiSchema? fullSchema = schemaRepository.Schemas[oldSchemaId];
schemaRepository.Schemas.Remove(oldSchemaId);
schemaRepository.Schemas.Add(newSchemaId, fullSchema);
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SetSchemaTypeToObjectDocumentFilter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SetSchemaTypeToObjectDocumentFilter.cs
index 2764f868e6..69aef99066 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SetSchemaTypeToObjectDocumentFilter.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SetSchemaTypeToObjectDocumentFilter.cs
@@ -11,12 +11,15 @@ internal sealed class SetSchemaTypeToObjectDocumentFilter : IDocumentFilter
public void Apply(OpenApiDocument document, DocumentFilterContext context)
{
- foreach (OpenApiSchema schema in document.Components.Schemas.Values)
+ if (document.Components?.Schemas != null)
{
- if (schema.Extensions.ContainsKey(RequiresRootObjectTypeKey))
+ foreach (OpenApiSchema schema in document.Components.Schemas.Values.OfType())
{
- schema.Type = "object";
- schema.Extensions.Remove(RequiresRootObjectTypeKey);
+ if (schema.Extensions != null && schema.Extensions.ContainsKey(RequiresRootObjectTypeKey))
+ {
+ schema.Type = JsonSchemaType.Object;
+ schema.Extensions.Remove(RequiresRootObjectTypeKey);
+ }
}
}
}
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SortSchemasFilter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SortSchemasFilter.cs
new file mode 100644
index 0000000000..1b90db881e
--- /dev/null
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SortSchemasFilter.cs
@@ -0,0 +1,57 @@
+using JetBrains.Annotations;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
+using Microsoft.OpenApi.Models.References;
+using Swashbuckle.AspNetCore.SwaggerGen;
+
+namespace JsonApiDotNetCore.OpenApi.Swashbuckle;
+
+[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
+internal sealed class SortSchemasFilter : IDocumentFilter
+{
+ // Should use SwaggerGeneratorOptions.SchemaComparer
+ private static readonly StringComparer DefaultStringComparer = StringComparer.Ordinal;
+
+ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
+ {
+ // Workaround for the change that ordering is no longer applied. See https://github.com/microsoft/OpenAPI.NET/issues/1314#issuecomment-2836828481.
+ // Pending: https://github.com/microsoft/OpenAPI.NET/issues/2342
+
+ swaggerDoc.Components ??= new OpenApiComponents();
+
+ if (swaggerDoc.Components.Schemas != null)
+ {
+ swaggerDoc.Components.Schemas = new SortedDictionary(swaggerDoc.Components.Schemas, DefaultStringComparer).ToDictionary();
+
+ foreach (IOpenApiSchema schema in swaggerDoc.Components.Schemas.Values)
+ {
+ SortSchema(schema);
+ }
+ }
+ }
+
+ private static void SortSchema(IOpenApiSchema schema)
+ {
+ if (schema is OpenApiSchema concreteSchema)
+ {
+ if (concreteSchema.Required != null)
+ {
+ concreteSchema.Required = new SortedSet(concreteSchema.Required, DefaultStringComparer).ToHashSet();
+ }
+
+ if (concreteSchema.Discriminator?.Mapping != null)
+ {
+ concreteSchema.Discriminator.Mapping =
+ new SortedDictionary(concreteSchema.Discriminator.Mapping, DefaultStringComparer).ToDictionary();
+ }
+
+ if (concreteSchema.AllOf != null)
+ {
+ foreach (IOpenApiSchema subSchema in concreteSchema.AllOf)
+ {
+ SortSchema(subSchema);
+ }
+ }
+ }
+ }
+}
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/DocumentationOpenApiOperationFilter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/DocumentationOpenApiOperationFilter.cs
index 1b5c0d5f4c..1e1ea7b6cc 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/DocumentationOpenApiOperationFilter.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/DocumentationOpenApiOperationFilter.cs
@@ -9,10 +9,12 @@
using JsonApiDotNetCore.Resources.Annotations;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.Net.Http.Headers;
-using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
using Swashbuckle.AspNetCore.SwaggerGen;
+#pragma warning disable AV1568 // Parameter value should not be overwritten in method body
+
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents;
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
@@ -78,7 +80,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context)
if (hasHeadVerb)
{
- operation.Responses.Clear();
+ operation.Responses?.Clear();
}
MethodInfo actionMethod = context.ApiDescription.ActionDescriptor.GetActionMethod();
@@ -162,7 +164,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context)
private static void ApplyGetPrimary(OpenApiOperation operation, ResourceType resourceType, bool hasHeadVerb)
{
- if (operation.Parameters.Count == 0)
+ if (operation.Parameters == null || operation.Parameters.Count == 0)
{
if (hasHeadVerb)
{
@@ -192,7 +194,7 @@ private static void ApplyGetPrimary(OpenApiOperation operation, ResourceType res
}
else if (operation.Parameters.Count == 1)
{
- string singularName = resourceType.PublicName.Singularize();
+ string? singularName = resourceType.PublicName.Singularize();
if (hasHeadVerb)
{
@@ -223,7 +225,7 @@ private static void ApplyGetPrimary(OpenApiOperation operation, ResourceType res
private void ApplyPostResource(OpenApiOperation operation, ResourceType resourceType)
{
- string singularName = resourceType.PublicName.Singularize();
+ string? singularName = resourceType.PublicName.Singularize();
SetOperationSummary(operation, $"Creates a new {singularName}.");
AddQueryStringParameters(operation, false);
@@ -253,10 +255,10 @@ private void ApplyPostResource(OpenApiOperation operation, ResourceType resource
private void ApplyPatchResource(OpenApiOperation operation, ResourceType resourceType)
{
- string singularName = resourceType.PublicName.Singularize();
+ string? singularName = resourceType.PublicName.Singularize();
SetOperationSummary(operation, $"Updates an existing {singularName}.");
- SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularName} to update.");
+ SetParameterDescription(operation.Parameters![0], $"The identifier of the {singularName} to update.");
AddQueryStringParameters(operation, false);
SetRequestBodyDescription(operation.RequestBody,
@@ -276,18 +278,18 @@ private void ApplyPatchResource(OpenApiOperation operation, ResourceType resourc
private void ApplyDeleteResource(OpenApiOperation operation, ResourceType resourceType)
{
- string singularName = resourceType.PublicName.Singularize();
+ string? singularName = resourceType.PublicName.Singularize();
SetOperationSummary(operation, $"Deletes an existing {singularName} by its identifier.");
- SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularName} to delete.");
+ SetParameterDescription(operation.Parameters![0], $"The identifier of the {singularName} to delete.");
SetResponseDescription(operation.Responses, HttpStatusCode.NoContent, $"The {singularName} was successfully deleted.");
SetResponseDescription(operation.Responses, HttpStatusCode.NotFound, $"The {singularName} does not exist.");
}
private static void ApplyGetSecondary(OpenApiOperation operation, RelationshipAttribute relationship, bool hasHeadVerb)
{
- string singularLeftName = relationship.LeftType.PublicName.Singularize();
- string rightName = relationship is HasOneAttribute ? relationship.RightType.PublicName.Singularize() : relationship.RightType.PublicName;
+ string? singularLeftName = relationship.LeftType.PublicName.Singularize();
+ string? rightName = relationship is HasOneAttribute ? relationship.RightType.PublicName.Singularize() : relationship.RightType.PublicName;
if (hasHeadVerb)
{
@@ -317,7 +319,7 @@ relationship is HasOneAttribute
SetResponseHeaderETag(operation.Responses, HttpStatusCode.NotModified);
}
- SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularLeftName} whose related {rightName} to retrieve.");
+ SetParameterDescription(operation.Parameters![0], $"The identifier of the {singularLeftName} whose related {rightName} to retrieve.");
AddQueryStringParameters(operation, false);
AddRequestHeaderIfNoneMatch(operation);
SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextQueryStringBad);
@@ -326,8 +328,8 @@ relationship is HasOneAttribute
private static void ApplyGetRelationship(OpenApiOperation operation, RelationshipAttribute relationship, bool hasHeadVerb)
{
- string singularLeftName = relationship.LeftType.PublicName.Singularize();
- string singularRightName = relationship.RightType.PublicName.Singularize();
+ string? singularLeftName = relationship.LeftType.PublicName.Singularize();
+ string? singularRightName = relationship.RightType.PublicName.Singularize();
string ident = relationship is HasOneAttribute ? "identity" : "identities";
if (hasHeadVerb)
@@ -359,7 +361,7 @@ relationship is HasOneAttribute
SetResponseHeaderETag(operation.Responses, HttpStatusCode.NotModified);
}
- SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularLeftName} whose related {singularRightName} {ident} to retrieve.");
+ SetParameterDescription(operation.Parameters![0], $"The identifier of the {singularLeftName} whose related {singularRightName} {ident} to retrieve.");
AddQueryStringParameters(operation, true);
AddRequestHeaderIfNoneMatch(operation);
SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextQueryStringBad);
@@ -368,11 +370,11 @@ relationship is HasOneAttribute
private void ApplyPostRelationship(OpenApiOperation operation, RelationshipAttribute relationship)
{
- string singularLeftName = relationship.LeftType.PublicName.Singularize();
+ string? singularLeftName = relationship.LeftType.PublicName.Singularize();
string rightName = relationship.RightType.PublicName;
SetOperationSummary(operation, $"Adds existing {rightName} to the {relationship} relationship of an individual {singularLeftName}.");
- SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularLeftName} to add {rightName} to.");
+ SetParameterDescription(operation.Parameters![0], $"The identifier of the {singularLeftName} to add {rightName} to.");
SetRequestBodyDescription(operation.RequestBody, $"The identities of the {rightName} to add to the {relationship} relationship.");
SetResponseDescription(operation.Responses, HttpStatusCode.NoContent,
@@ -387,8 +389,8 @@ private void ApplyPostRelationship(OpenApiOperation operation, RelationshipAttri
private void ApplyPatchRelationship(OpenApiOperation operation, RelationshipAttribute relationship)
{
bool isOptional = _resourceFieldValidationMetadataProvider.IsNullable(relationship);
- string singularLeftName = relationship.LeftType.PublicName.Singularize();
- string rightName = relationship is HasOneAttribute ? relationship.RightType.PublicName.Singularize() : relationship.RightType.PublicName;
+ string? singularLeftName = relationship.LeftType.PublicName.Singularize();
+ string? rightName = relationship is HasOneAttribute ? relationship.RightType.PublicName.Singularize() : relationship.RightType.PublicName;
SetOperationSummary(operation,
relationship is HasOneAttribute
@@ -397,7 +399,7 @@ relationship is HasOneAttribute
: $"Assigns an existing {rightName} to the {relationship} relationship of an individual {singularLeftName}."
: $"Assigns existing {rightName} to the {relationship} relationship of an individual {singularLeftName}.");
- SetParameterDescription(operation.Parameters[0],
+ SetParameterDescription(operation.Parameters![0],
isOptional
? $"The identifier of the {singularLeftName} whose {relationship} relationship to assign or clear."
: $"The identifier of the {singularLeftName} whose {relationship} relationship to assign.");
@@ -420,11 +422,11 @@ relationship is HasOneAttribute
private void ApplyDeleteRelationship(OpenApiOperation operation, RelationshipAttribute relationship)
{
- string singularLeftName = relationship.LeftType.PublicName.Singularize();
+ string? singularLeftName = relationship.LeftType.PublicName.Singularize();
string rightName = relationship.RightType.PublicName;
SetOperationSummary(operation, $"Removes existing {rightName} from the {relationship} relationship of an individual {singularLeftName}.");
- SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularLeftName} to remove {rightName} from.");
+ SetParameterDescription(operation.Parameters![0], $"The identifier of the {singularLeftName} to remove {rightName} from.");
SetRequestBodyDescription(operation.RequestBody, $"The identities of the {rightName} to remove from the {relationship} relationship.");
SetResponseDescription(operation.Responses, HttpStatusCode.NoContent,
@@ -454,64 +456,76 @@ private static void SetOperationRemarks(OpenApiOperation operation, string descr
operation.Description = XmlCommentsTextHelper.Humanize(description);
}
- private static void SetParameterDescription(OpenApiParameter parameter, string description)
+ private static void SetParameterDescription(IOpenApiParameter parameter, string description)
{
parameter.Description = XmlCommentsTextHelper.Humanize(description);
}
- private static void SetRequestBodyDescription(OpenApiRequestBody requestBody, string description)
+ private static void SetRequestBodyDescription(IOpenApiRequestBody? requestBody, string description)
{
+ requestBody ??= new OpenApiRequestBody();
requestBody.Description = XmlCommentsTextHelper.Humanize(description);
}
- private static void SetResponseDescription(OpenApiResponses responses, HttpStatusCode statusCode, string description)
+ private static void SetResponseDescription(OpenApiResponses? responses, HttpStatusCode statusCode, string description)
{
+ responses ??= new OpenApiResponses();
+
OpenApiResponse response = GetOrAddResponse(responses, statusCode);
response.Description = XmlCommentsTextHelper.Humanize(description);
}
- private static void SetResponseHeaderETag(OpenApiResponses responses, HttpStatusCode statusCode)
+ private static void SetResponseHeaderETag(OpenApiResponses? responses, HttpStatusCode statusCode)
{
+ responses ??= new OpenApiResponses();
OpenApiResponse response = GetOrAddResponse(responses, statusCode);
+ response.Headers ??= [];
+
response.Headers[HeaderNames.ETag] = new OpenApiHeader
{
Description = "A fingerprint of the HTTP response, which can be used in an If-None-Match header to only fetch changes.",
Required = true,
Schema = new OpenApiSchema
{
- Type = "string"
+ Type = JsonSchemaType.String
}
};
}
- private static void SetResponseHeaderContentLength(OpenApiResponses responses, HttpStatusCode statusCode)
+ private static void SetResponseHeaderContentLength(OpenApiResponses? responses, HttpStatusCode statusCode)
{
+ responses ??= new OpenApiResponses();
OpenApiResponse response = GetOrAddResponse(responses, statusCode);
+ response.Headers ??= [];
+
response.Headers[HeaderNames.ContentLength] = new OpenApiHeader
{
Description = "Size of the HTTP response body, in bytes.",
Required = true,
Schema = new OpenApiSchema
{
- Type = "integer",
+ Type = JsonSchemaType.Integer,
Format = "int64"
}
};
}
- private static void SetResponseHeaderLocation(OpenApiResponses responses, HttpStatusCode statusCode, string resourceName)
+ private static void SetResponseHeaderLocation(OpenApiResponses? responses, HttpStatusCode statusCode, string resourceName)
{
+ responses ??= new OpenApiResponses();
OpenApiResponse response = GetOrAddResponse(responses, statusCode);
+ response.Headers ??= [];
+
response.Headers[HeaderNames.Location] = new OpenApiHeader
{
Description = $"The URL at which the newly created {resourceName} can be retrieved.",
Required = true,
Schema = new OpenApiSchema
{
- Type = "string",
+ Type = JsonSchemaType.String,
Format = "uri"
}
};
@@ -521,13 +535,15 @@ private static OpenApiResponse GetOrAddResponse(OpenApiResponses responses, Http
{
string responseCode = ((int)statusCode).ToString();
- if (!responses.TryGetValue(responseCode, out OpenApiResponse? response))
+ if (!responses.TryGetValue(responseCode, out IOpenApiResponse? response) || response is not OpenApiResponse)
{
response = new OpenApiResponse();
responses.Add(responseCode, response);
}
- return response;
+ var concreteResponse = (OpenApiResponse)response;
+ concreteResponse.Headers ??= new Dictionary();
+ return concreteResponse;
}
private static void AddQueryStringParameters(OpenApiOperation operation, bool isRelationshipEndpoint)
@@ -542,20 +558,21 @@ private static void AddQueryStringParameters(OpenApiOperation operation, bool is
// - This makes NSwag produce a C# client with method signature: GetAsync(IDictionary? query)
// when combined with true in the project file.
+ operation.Parameters ??= [];
+
operation.Parameters.Add(new OpenApiParameter
{
In = ParameterLocation.Query,
Name = "query",
Schema = new OpenApiSchema
{
- Type = "object",
+ Type = JsonSchemaType.Object,
AdditionalProperties = new OpenApiSchema
{
- Type = "string",
- Nullable = true
+ Type = JsonSchemaType.String | JsonSchemaType.Null
},
// Prevent SwaggerUI from producing sample, which fails when used because unknown query string parameters are blocked by default.
- Example = new OpenApiString(string.Empty)
+ Example = string.Empty
},
Description = isRelationshipEndpoint ? RelationshipQueryStringParameters : ResourceQueryStringParameters
});
@@ -563,6 +580,8 @@ private static void AddQueryStringParameters(OpenApiOperation operation, bool is
private static void AddRequestHeaderIfNoneMatch(OpenApiOperation operation)
{
+ operation.Parameters ??= [];
+
operation.Parameters.Add(new OpenApiParameter
{
In = ParameterLocation.Header,
@@ -570,7 +589,7 @@ private static void AddRequestHeaderIfNoneMatch(OpenApiOperation operation)
Description = "A list of ETags, resulting in HTTP status 304 without a body, if one of them matches the current fingerprint.",
Schema = new OpenApiSchema
{
- Type = "string"
+ Type = JsonSchemaType.String
}
});
}
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/EndpointOrderingFilter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/EndpointOrderingFilter.cs
index 047ba4355a..fdeb97018b 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/EndpointOrderingFilter.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/EndpointOrderingFilter.cs
@@ -1,6 +1,8 @@
using System.Text.RegularExpressions;
using JetBrains.Annotations;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
+using Microsoft.OpenApi.Models.References;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents;
@@ -13,28 +15,43 @@ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
ArgumentNullException.ThrowIfNull(swaggerDoc);
ArgumentNullException.ThrowIfNull(context);
- KeyValuePair[] endpointsInOrder = swaggerDoc.Paths.OrderBy(GetPrimaryResourcePublicName)
+ KeyValuePair[] endpointsInOrder = swaggerDoc.Paths.OrderBy(GetPrimaryResourcePublicName)
.ThenBy(GetRelationshipName).ThenBy(IsSecondaryEndpoint).ToArray();
- swaggerDoc.Paths.Clear();
+ swaggerDoc.Paths = new OpenApiPaths();
- foreach ((string url, OpenApiPathItem path) in endpointsInOrder)
+ foreach ((string url, IOpenApiPathItem path) in endpointsInOrder)
{
swaggerDoc.Paths.Add(url, path);
}
}
- private static string GetPrimaryResourcePublicName(KeyValuePair entry)
+ private static string GetPrimaryResourcePublicName(KeyValuePair entry)
{
- return entry.Value.Operations.First().Value.Tags.First().Name;
+ if (entry.Value.Operations is { Count: > 0 })
+ {
+ ISet? references = entry.Value.Operations.First().Value.Tags;
+
+ if (references is { Count: > 0 })
+ {
+ OpenApiTagReference openApiTagReference = references.First();
+
+ if (openApiTagReference.Name != null)
+ {
+ return openApiTagReference.Name;
+ }
+ }
+ }
+
+ throw new InvalidOperationException($"Failed to find tag value for endpoint '{entry.Key}'.");
}
- private static bool IsSecondaryEndpoint(KeyValuePair entry)
+ private static bool IsSecondaryEndpoint(KeyValuePair entry)
{
return entry.Key.Contains("/relationships");
}
- private static string GetRelationshipName(KeyValuePair entry)
+ private static string GetRelationshipName(KeyValuePair entry)
{
Match match = RelationshipNameInUrlRegex().Match(entry.Key);
diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/JsonApiDataContractResolver.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/JsonApiDataContractResolver.cs
index dcc652c696..ba1cc86d99 100644
--- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/JsonApiDataContractResolver.cs
+++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/JsonApiDataContractResolver.cs
@@ -33,7 +33,7 @@ public DataContract GetDataContractForType(Type type)
return DataContract.ForDynamic(typeof(object));
}
- DataContract dataContract = _dataContractResolver.GetDataContractForType(type);
+ DataContract? dataContract = _dataContractResolver.GetDataContractForType(type);
IList? replacementProperties = null;
@@ -61,7 +61,7 @@ private List GetDataPropertiesThatExistInResourceClrType(Type reso
ResourceType resourceType = _resourceGraph.GetResourceType(resourceClrType);
List dataProperties = [];
- foreach (DataProperty property in dataContract.ObjectProperties)
+ foreach (DataProperty? property in dataContract.ObjectProperties)
{
if (property.MemberInfo.Name == nameof(Identifiable