Support OpenAPI polymorphic output with JsonDerivedType (#16144)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
namespace Umbraco.Cms.Api.Management.OpenApi;
|
||||
namespace Umbraco.Cms.Api.Common.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// Marker interface that ensure the type have a "$type" discriminator in the open api schema.
|
||||
@@ -5,4 +5,6 @@ namespace Umbraco.Cms.Api.Common.Serialization;
|
||||
public interface IUmbracoJsonTypeInfoResolver : IJsonTypeInfoResolver
|
||||
{
|
||||
IEnumerable<Type> FindSubTypes(Type type);
|
||||
|
||||
string? GetTypeDiscriminatorValue(Type type);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using Umbraco.Cms.Api.Common.OpenApi;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Api.Common.Serialization;
|
||||
|
||||
@@ -15,6 +18,14 @@ public sealed class UmbracoJsonTypeInfoResolver : DefaultJsonTypeInfoResolver, I
|
||||
|
||||
public IEnumerable<Type> FindSubTypes(Type type)
|
||||
{
|
||||
JsonDerivedTypeAttribute[] explicitJsonDerivedTypes = type
|
||||
.GetCustomAttributes<JsonDerivedTypeAttribute>(false)
|
||||
.ToArray();
|
||||
if (explicitJsonDerivedTypes.Any())
|
||||
{
|
||||
return explicitJsonDerivedTypes.Select(a => a.DerivedType);
|
||||
}
|
||||
|
||||
if (type.IsInterface is false)
|
||||
{
|
||||
// IMPORTANT: do NOT return an empty enumerable here. it will cause nullability to fail on reference
|
||||
@@ -33,6 +44,24 @@ public sealed class UmbracoJsonTypeInfoResolver : DefaultJsonTypeInfoResolver, I
|
||||
return result;
|
||||
}
|
||||
|
||||
public string? GetTypeDiscriminatorValue(Type type)
|
||||
{
|
||||
JsonDerivedTypeAttribute? jsonDerivedTypeAttribute = type
|
||||
.GetBaseTypes(false)
|
||||
.WhereNotNull()
|
||||
.SelectMany(baseType => baseType.GetCustomAttributes<JsonDerivedTypeAttribute>(false))
|
||||
.FirstOrDefault(attr => attr.DerivedType == type);
|
||||
|
||||
if (jsonDerivedTypeAttribute is not null)
|
||||
{
|
||||
// IMPORTANT: do NOT perform fallback to type.Name here - it will work for the schema generation,
|
||||
// but not for the actual serialization, and then it's only going to cause confusion.
|
||||
return jsonDerivedTypeAttribute.TypeDiscriminator?.ToString();
|
||||
}
|
||||
|
||||
return typeof(IOpenApiDiscriminator).IsAssignableFrom(type) ? type.Name : null;
|
||||
}
|
||||
|
||||
public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
|
||||
{
|
||||
JsonTypeInfo result = base.GetTypeInfo(type, options);
|
||||
|
||||
@@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Umbraco.Cms.Api.Common.OpenApi;
|
||||
using Umbraco.Cms.Api.Common.Serialization;
|
||||
using Umbraco.Cms.Api.Management.DependencyInjection;
|
||||
using Umbraco.Cms.Api.Management.OpenApi;
|
||||
@@ -34,8 +35,8 @@ public class ConfigureUmbracoManagementApiSwaggerGenOptions : IConfigureOptions<
|
||||
swaggerGenOptions.UseOneOfForPolymorphism();
|
||||
|
||||
// Ensure all types that implements the IOpenApiDiscriminator have a $type property in the OpenApi schema with the default value (The class name) that is expected by the server
|
||||
swaggerGenOptions.SelectDiscriminatorNameUsing(type => typeof(IOpenApiDiscriminator).IsAssignableFrom(type) ? "$type" : null);
|
||||
swaggerGenOptions.SelectDiscriminatorValueUsing(type => typeof(IOpenApiDiscriminator).IsAssignableFrom(type) ? type.Name : null);
|
||||
swaggerGenOptions.SelectDiscriminatorNameUsing(type => _umbracoJsonTypeInfoResolver.GetTypeDiscriminatorValue(type) is not null ? "$type" : null);
|
||||
swaggerGenOptions.SelectDiscriminatorValueUsing(_umbracoJsonTypeInfoResolver.GetTypeDiscriminatorValue);
|
||||
|
||||
|
||||
swaggerGenOptions.AddSecurityDefinition(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Umbraco.Cms.Api.Management.OpenApi;
|
||||
using Umbraco.Cms.Api.Common.OpenApi;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.UserGroup.Permissions;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user