Skip to content

Commit a9eb1fb

Browse files
committed
Add support for AddOpenApiOperationTransformer API
1 parent cd5ca69 commit a9eb1fb

File tree

4 files changed

+79
-0
lines changed

4 files changed

+79
-0
lines changed

src/OpenApi/src/Extensions/OpenApiEndpointConventionBuilderExtensions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,17 @@ private static void AddAndConfigureOperationForEndpoint(EndpointBuilder endpoint
121121
}
122122
}
123123
}
124+
125+
/// <summary>
126+
/// Adds an OpenAPI operation transformer to the <see cref="EndpointBuilder.Metadata" /> associated
127+
/// with the current endpoint.
128+
/// </summary>
129+
/// <param name="builder">The <see cref="IEndpointConventionBuilder"/>.</param>
130+
/// <param name="transformer">The <see cref="Func{OpenApiOperation, OpenApiOperationTransformerContext, CancellationToken, Task}"/> that modifies the operation in the <see cref="OpenApiDocument"/>.</param>
131+
/// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
132+
public static TBuilder AddOpenApiOperationTransformer<TBuilder>(this TBuilder builder, Func<OpenApiOperation, OpenApiOperationTransformerContext, CancellationToken, Task> transformer) where TBuilder : IEndpointConventionBuilder
133+
{
134+
builder.WithMetadata(new DelegateOpenApiOperationTransformer(transformer));
135+
return builder;
136+
}
124137
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
#nullable enable
2+
static Microsoft.AspNetCore.Builder.OpenApiEndpointConventionBuilderExtensions.AddOpenApiOperationTransformer<TBuilder>(this TBuilder builder, System.Func<Microsoft.OpenApi.Models.OpenApiOperation!, Microsoft.AspNetCore.OpenApi.OpenApiOperationTransformerContext!, System.Threading.CancellationToken, System.Threading.Tasks.Task!>! transformer) -> TBuilder

src/OpenApi/src/Services/OpenApiDocumentService.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,16 @@ private async Task<Dictionary<OperationType, OpenApiOperation>> GetOperationsAsy
268268
var transformer = operationTransformers[i];
269269
await transformer.TransformAsync(operation, operationContext, cancellationToken);
270270
}
271+
272+
// Apply any endpoint-specific operation transformers registered via
273+
// the AddOpenApiOperationTransformer extension method.
274+
var endpointOperationTransformer = description.ActionDescriptor.EndpointMetadata
275+
.OfType<DelegateOpenApiOperationTransformer>()
276+
.LastOrDefault();
277+
if (endpointOperationTransformer is not null)
278+
{
279+
await endpointOperationTransformer.TransformAsync(operation, operationContext, cancellationToken);
280+
}
271281
}
272282
return operations;
273283
}

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Transformers/OperationTransformerTests.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,61 @@ public async Task OperationTransformer_CanAccessTransientServiceFromContextAppli
478478
Assert.Equal(4, Dependency.InstantiationCount);
479479
}
480480

481+
[Fact]
482+
public async Task WithOpenApi_CanApplyTransformer()
483+
{
484+
var builder = CreateBuilder();
485+
486+
builder.MapGet("/", () => { })
487+
.AddOpenApiOperationTransformer((operation, context, cancellationToken) =>
488+
{
489+
operation.Description = "Operation Description";
490+
return Task.CompletedTask;
491+
});
492+
493+
await VerifyOpenApiDocument(builder, document =>
494+
{
495+
Assert.Collection(document.Paths.OrderBy(p => p.Key),
496+
path =>
497+
{
498+
Assert.Equal("/", path.Key);
499+
var operation = Assert.Single(path.Value.Operations.Values);
500+
Assert.Equal("Operation Description", operation.Description);
501+
});
502+
});
503+
}
504+
505+
[Fact]
506+
public async Task WithOpenApi_TransformerRunsAfterOtherTransformers()
507+
{
508+
var builder = CreateBuilder();
509+
510+
builder.MapGet("/", () => { })
511+
.AddOpenApiOperationTransformer((operation, context, cancellationToken) =>
512+
{
513+
operation.Description = "Operation Description";
514+
return Task.CompletedTask;
515+
});
516+
517+
var options = new OpenApiOptions();
518+
options.AddOperationTransformer((operation, context, cancellationToken) =>
519+
{
520+
operation.Description = "Operation Description 2";
521+
return Task.CompletedTask;
522+
});
523+
524+
await VerifyOpenApiDocument(builder, document =>
525+
{
526+
Assert.Collection(document.Paths.OrderBy(p => p.Key),
527+
path =>
528+
{
529+
Assert.Equal("/", path.Key);
530+
var operation = Assert.Single(path.Value.Operations.Values);
531+
Assert.Equal("Operation Description", operation.Description);
532+
});
533+
});
534+
}
535+
481536
private class ActivatedTransformer : IOpenApiOperationTransformer
482537
{
483538
public Task TransformAsync(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken)

0 commit comments

Comments
 (0)