Skip to content

Commit 65f941f

Browse files
Add OpenApiVersionSelector
See dotnet#62193 (comment)
1 parent 7c6d827 commit 65f941f

File tree

19 files changed

+41
-46
lines changed

19 files changed

+41
-46
lines changed

src/OpenApi/sample/Program.cs

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,26 @@
2121
options.SerializerOptions.NumberHandling = JsonNumberHandling.Strict;
2222
});
2323

24+
Func<HttpContext, OpenApiSpecVersion?> versionSelector = (context) =>
25+
{
26+
if (context.Request.Query["version"] is { Count: 1 } version &&
27+
Enum.TryParse<OpenApiSpecVersion>(version, out var result))
28+
{
29+
return result;
30+
}
31+
32+
return null;
33+
};
34+
2435
builder.Services.AddOpenApi("v1", options =>
2536
{
37+
options.OpenApiVersionSelector = versionSelector;
2638
options.AddHeader("X-Version", "1.0");
2739
options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
2840
});
2941
builder.Services.AddOpenApi("v2", options =>
3042
{
43+
options.OpenApiVersionSelector = versionSelector;
3144
options.AddSchemaTransformer<AddExternalDocsTransformer>();
3245
options.AddOperationTransformer<AddExternalDocsTransformer>();
3346
options.AddDocumentTransformer(new AddContactTransformer());
@@ -53,37 +66,9 @@
5366
"xml",
5467
};
5568

56-
foreach (var version in versions)
69+
foreach (var name in documentNames)
5770
{
58-
builder.Services.AddOpenApi($"v1-{version}", options =>
59-
{
60-
options.OpenApiVersion = version;
61-
options.ShouldInclude = (description) => description.GroupName == null || description.GroupName == "v1";
62-
options.AddHeader("X-Version", "1.0");
63-
options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
64-
});
65-
builder.Services.AddOpenApi($"v2-{version}", options =>
66-
{
67-
options.OpenApiVersion = version;
68-
options.ShouldInclude = (description) => description.GroupName == null || description.GroupName == "v2";
69-
options.AddSchemaTransformer<AddExternalDocsTransformer>();
70-
options.AddOperationTransformer<AddExternalDocsTransformer>();
71-
options.AddDocumentTransformer(new AddContactTransformer());
72-
options.AddDocumentTransformer((document, context, token) =>
73-
{
74-
document.Info.License = new OpenApiLicense { Name = "MIT" };
75-
return Task.CompletedTask;
76-
});
77-
});
78-
79-
foreach (var name in documentNames)
80-
{
81-
builder.Services.AddOpenApi($"{name}-{version}", options =>
82-
{
83-
options.OpenApiVersion = version;
84-
options.ShouldInclude = (description) => description.GroupName == null || description.GroupName == name;
85-
});
86-
}
71+
builder.Services.AddOpenApi(name, (options) => options.OpenApiVersionSelector = versionSelector);
8772
}
8873

8974
var app = builder.Build();

src/OpenApi/src/Extensions/OpenApiEndpointRouteBuilderExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.AspNetCore.Routing;
99
using Microsoft.Extensions.DependencyInjection;
1010
using Microsoft.Extensions.Options;
11+
using Microsoft.OpenApi;
1112
using Microsoft.OpenApi.Extensions;
1213
using Microsoft.OpenApi.Writers;
1314

@@ -53,6 +54,7 @@ public static IEndpointConventionBuilder MapOpenApi(this IEndpointRouteBuilder e
5354
{
5455
var document = await documentService.GetOpenApiDocumentAsync(context.RequestServices, context.Request, context.RequestAborted);
5556
var documentOptions = options.Get(lowercasedDocumentName);
57+
var openApiVersion = documentOptions.OpenApiVersionSelector?.Invoke(context) ?? documentOptions.OpenApiVersion;
5658

5759
using var textWriter = new Utf8BufferTextWriter(System.Globalization.CultureInfo.InvariantCulture);
5860
textWriter.SetWriter(context.Response.BodyWriter);
@@ -74,7 +76,7 @@ public static IEndpointConventionBuilder MapOpenApi(this IEndpointRouteBuilder e
7476
context.Response.ContentType = contentType;
7577

7678
await context.Response.StartAsync();
77-
await document.SerializeAsync(openApiWriter, documentOptions.OpenApiVersion, context.RequestAborted);
79+
await document.SerializeAsync(openApiWriter, openApiVersion, context.RequestAborted);
7880
await context.Response.BodyWriter.FlushAsync(context.RequestAborted);
7981
}
8082
}).ExcludeFromDescription();

src/OpenApi/src/PublicAPI.Unshipped.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#nullable enable
22
Microsoft.AspNetCore.OpenApi.IOpenApiDocumentProvider
33
Microsoft.AspNetCore.OpenApi.IOpenApiDocumentProvider.GetOpenApiDocumentAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Microsoft.OpenApi.Models.OpenApiDocument!>!
4+
Microsoft.AspNetCore.OpenApi.OpenApiOptions.OpenApiVersionSelector.get -> System.Func<Microsoft.AspNetCore.Http.HttpContext!, Microsoft.OpenApi.OpenApiSpecVersion?>?
5+
Microsoft.AspNetCore.OpenApi.OpenApiOptions.OpenApiVersionSelector.set -> void
46
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
57
Microsoft.AspNetCore.OpenApi.OpenApiDocumentTransformerContext.GetOrCreateSchemaAsync(System.Type! type, Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription? parameterDescription = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Microsoft.OpenApi.Models.OpenApiSchema!>!
68
Microsoft.AspNetCore.OpenApi.OpenApiOperationTransformerContext.Document.get -> Microsoft.OpenApi.Models.OpenApiDocument?

src/OpenApi/src/Services/OpenApiOptions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Diagnostics.CodeAnalysis;
55
using System.Text.Json.Serialization.Metadata;
6+
using Microsoft.AspNetCore.Http;
67
using Microsoft.AspNetCore.Mvc.ApiExplorer;
78
using Microsoft.OpenApi;
89
using Microsoft.OpenApi.Models;
@@ -39,6 +40,11 @@ public OpenApiOptions()
3940
/// </summary>
4041
public OpenApiSpecVersion OpenApiVersion { get; set; } = OpenApiSpecVersion.OpenApi3_1;
4142

43+
/// <summary>
44+
/// An optional delegate to determine the OpenAPI version to use for the current HTTP request.
45+
/// </summary>
46+
public Func<HttpContext, OpenApiSpecVersion?>? OpenApiVersionSelector { get; set; }
47+
4248
/// <summary>
4349
/// The name of the OpenAPI document this <see cref="OpenApiOptions"/> instance is associated with.
4450
/// </summary>

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/OpenApiDocumentIntegrationTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public async Task VerifyOpenApiDocument(string documentName, OpenApiSpecVersion
3737
{
3838
var versionString = version.ToString();
3939
using var client = fixture.CreateClient();
40-
var json = await client.GetStringAsync($"/openapi/{documentName}-{versionString}.json");
40+
var json = await client.GetStringAsync($"/openapi/{documentName}.json?version={versionString}");
4141
var baseSnapshotsDirectory = SkipOnHelixAttribute.OnHelix()
4242
? Path.Combine(Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT"), "Integration", "snapshots")
4343
: "snapshots";

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_0/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=controllers.verified.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"openapi": "3.0.4",
33
"info": {
4-
"title": "Sample | controllers-openapi3_0",
4+
"title": "Sample | controllers",
55
"version": "1.0.0"
66
},
77
"servers": [

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_0/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=forms.verified.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"openapi": "3.0.4",
33
"info": {
4-
"title": "Sample | forms-openapi3_0",
4+
"title": "Sample | forms",
55
"version": "1.0.0"
66
},
77
"servers": [

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_0/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=responses.verified.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"openapi": "3.0.4",
33
"info": {
4-
"title": "Sample | responses-openapi3_0",
4+
"title": "Sample | responses",
55
"version": "1.0.0"
66
},
77
"servers": [

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_0/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=schemas-by-ref.verified.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"openapi": "3.0.4",
33
"info": {
4-
"title": "Sample | schemas-by-ref-openapi3_0",
4+
"title": "Sample | schemas-by-ref",
55
"version": "1.0.0"
66
},
77
"servers": [

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_0/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=v1.verified.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"openapi": "3.0.4",
33
"info": {
4-
"title": "Sample | v1-openapi3_0",
4+
"title": "Sample | v1",
55
"version": "1.0.0"
66
},
77
"servers": [

0 commit comments

Comments
 (0)