Expose additional info about properties and JSON types in OpenApiSchemaTransformerContext #56584
Closed
Description
Background and Motivation
OpenAPI schema transformers currently only run on schemas that are generated at the top-level for parameters and responses. For example, in the following case:
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options =>
{
options.UseSchemaTransformer((schema, context, ct) =>
{
if (context.Type == typeof(int))
{
schema.Format = "some-custom-format";
}
}
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/todos/{id}", (int id) => Results.Ok<Todo>(new Todo()));
public record Todo(int Id, string Name, bool IsCompleted);
The transformer will only apply the modification on the schema generated for the id
route parameter and not the id
property within Todo
. To resolve this issue, schemas need to be applied recursively into properties and child schemas (like those in anyOf
and allOf
). To support this, the implementation will apply transformers on child schemas. As part of this work, we need to expose additional APIs on OpenApiSchemaTransformerContext
in order to be able to analyze
Proposed API
// Assembly: Microsoft.AspNetCore.OpenApi;
namespace Microsoft.AspNetCore.OpenApi;
public sealed class OpenApiSchemaTransformerContext
{
+ public JsonTypeInfo TypeInfo { get; init; }
+ public JsonPropertyInfo? PropertyInfo { get; init; }
}
Usage Examples
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options =>
{
options.UseSchemaTransformer((schema, context, ct) =>
{
if (context.Type == typeof(int))
{
if (context.PropertyInfo is { AttributeProvider: { } attributeProvider } jsonPropertyInfo)
{
if (attributeProvider.GetCustomAttributes(inherit: false).OfType<MyCustomAttribute>().LastOrDefault() is {} attr)
{
schema.Description = attr.Value;
}
}
schema.Format = "some-custom-format";
}
}
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/todos/{id}", (int id) => Results.Ok<Todo>(new Todo()));
public record Todo(int Id, string Name, bool IsCompleted);
Alternative Designs
- Provide
TypeInfo
andPropertyInfo
instead ofJsonTypeInfo
andJsonPropertyInfo
? - Should properties only expose public accessors instead of initializers as well?
Risks
- This API shape requires that users apply a null-check to disambiguate if they are in the schema for a property or not.
- This API shape does not provide a consistent way to determine if a sub-schema that is being generated is in the
anyOf
of a parent type.