Skip to content

Commit 27f2a01

Browse files
authored
Map all true schemas to empty object schemas in OpenAPI (#57067)
* Map all true schemas to empty object schemas in OpenAPI * Address feedback
1 parent 27ae082 commit 27f2a01

File tree

2 files changed

+73
-3
lines changed

2 files changed

+73
-3
lines changed

src/OpenApi/src/Services/Schemas/OpenApiSchemaService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ internal sealed class OpenApiSchemaService(
8282
};
8383
}
8484
// STJ uses `true` in place of an empty object to represent a schema that matches
85-
// anything. We override this default behavior here to match the style traditionally
86-
// expected in OpenAPI documents.
87-
if (type == typeof(object))
85+
// anything (like the `object` type) or types with user-defined converters. We override
86+
// this default behavior here to match the format expected in OpenAPI v3.
87+
if (schema.GetValueKind() == JsonValueKind.True)
8888
{
8989
schema = new JsonObject();
9090
}

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.ParameterSchemas.cs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33

44
using System.ComponentModel;
55
using System.ComponentModel.DataAnnotations;
6+
using System.Text.Json;
7+
using System.Text.Json.Serialization;
68
using Microsoft.AspNetCore.Builder;
79
using Microsoft.AspNetCore.Http;
810
using Microsoft.AspNetCore.Mvc;
11+
using Microsoft.AspNetCore.Routing;
12+
using Microsoft.Extensions.DependencyInjection;
913
using Microsoft.OpenApi.Any;
1014
using Microsoft.OpenApi.Models;
1115

@@ -462,4 +466,70 @@ private class RouteParamsWithValidationsContainer
462466
[MaxLength(5)]
463467
public string Name { get; set; }
464468
}
469+
470+
[Fact]
471+
public async Task SupportsParametersWithTypeConverter()
472+
{
473+
// Arrange
474+
var serviceCollection = new ServiceCollection();
475+
serviceCollection.ConfigureHttpJsonOptions(options =>
476+
{
477+
options.SerializerOptions.Converters.Add(new CustomTypeConverter());
478+
});
479+
var builder = CreateBuilder(serviceCollection);
480+
481+
// Act
482+
builder.MapPost("/api", (CustomType id) => { });
483+
484+
// Assert
485+
await VerifyOpenApiDocument(builder, document =>
486+
{
487+
var operation = document.Paths["/api"].Operations[OperationType.Post];
488+
Assert.NotNull(operation.RequestBody);
489+
Assert.NotNull(operation.RequestBody.Content);
490+
Assert.NotNull(operation.RequestBody.Content["application/json"]);
491+
Assert.NotNull(operation.RequestBody.Content["application/json"].Schema);
492+
// Type is null, it's up to the user to configure this via a custom schema
493+
// transformer for types with a converter.
494+
Assert.Null(operation.RequestBody.Content["application/json"].Schema.Type);
495+
});
496+
}
497+
498+
public struct CustomType { }
499+
500+
public class CustomTypeConverter : JsonConverter<CustomType>
501+
{
502+
public override CustomType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
503+
{
504+
return new CustomType();
505+
}
506+
507+
public override void Write(Utf8JsonWriter writer, CustomType value, JsonSerializerOptions options)
508+
{
509+
throw new NotImplementedException();
510+
}
511+
}
512+
513+
[Fact]
514+
public async Task SupportsParameterWithDynamicType()
515+
{
516+
// Arrange
517+
var builder = CreateBuilder();
518+
519+
// Act
520+
builder.MapPost("/api", (dynamic id) => { });
521+
522+
// Assert
523+
await VerifyOpenApiDocument(builder, document =>
524+
{
525+
var operation = document.Paths["/api"].Operations[OperationType.Post];
526+
Assert.NotNull(operation.RequestBody);
527+
Assert.NotNull(operation.RequestBody.Content);
528+
Assert.NotNull(operation.RequestBody.Content["application/json"]);
529+
Assert.NotNull(operation.RequestBody.Content["application/json"].Schema);
530+
// Type is null, it's up to the user to configure this via a custom schema
531+
// transformer for types with a converter.
532+
Assert.Null(operation.RequestBody.Content["application/json"].Schema.Type);
533+
});
534+
}
465535
}

0 commit comments

Comments
 (0)