Skip to content

Add support for an interface for OpenAPI operation transformations #56022

Closed
@martincostello

Description

@martincostello

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesfeature-openapi

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions