Description
Background and Motivation
In the new OpenAPI functionality in .NET 9 preview.4 there is a first-class interface for document transformations, IOpenApiDocumentTransformer
, but there isn't an analogous interface for operations.
It is possible to perform operation transformations by providing a lambda function, but this can quickly get complicated if you want to do things that are non-trivial, use dependencies from DI etc. compared to if you could encapsulate your logic in a class to perform a specific operation like is possible for document transforms.
Proposed API
namespace Microsoft.AspNetCore.OpenApi;
+/// <summary>
+/// Represents a transformer that can be used to modify an OpenAPI operation.
+/// </summary>
+public interface IOpenApiOperationTransformer
+{
+ Task TransformAsync(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken);
+}
public partial sealed class OpenApiOptions
{
+ public OpenApiOptions UseOperationTransformer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TTransformerType>()
+ where TTransformerType : IOpenApiOperationTransformer
+ public OpenApiOptions UseOperationTransformer(IOpenApiOperationTransformer transformer)
}
These would be implemented the same way the document support is, so that DI works as expected to activate the types, it's AoT-friendly etc.
Usage Examples
services.AddOpenApi("v1", (options) =>
{
options.UseOperationTransformer<MyOperationTransformer>();
});
public sealed class MyOperationTransformer(MyService someService, IConfiguration configuration) : IOpenApiOperationTransformer
{
public Task TransformAsync(
OpenApiOperation operation,
OpenApiOperationTransformerContext context,
CancellationToken cancellationToken)
{
if (configuration["DoWhatever"] == "true")
{
await someService.DoStuff(operation, cancellationToken);
}
}
}
Alternative Designs
Make the code that enumerates the operations re-usable to public callers so that if an operation interface isn't desired, then the user can implement a document transformer to easily enumerate the operations to do a transform in their custom implementation of the interface. Maybe a base class that implements IOpenApiDocumentTransformer
and applies the visitor pattern to allow the user to override methods to apply transforms:
namespace Microsoft.AspNetCore.OpenApi;
+public abstract class OpenApiOperationTransformer : IOpenApiDocumentTransformer
+{
+ protected OpenApiOperationTransformer();
+
+ public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken); // Enumerates the operations and calls TransformOperationAsync() for each
+
+ protected abstract Task TransformOperationAsync(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken);
}
Risks
Increased complexity of the OpenAPI generator implementation.