Add property to OpenApiOptions to allow dynamic OpenAPI version selection
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
## Background and Motivation
While working on https://github.com/dotnet/aspnetcore/pull/62193#discussion_r2128410638, I noticed that it isn't currently possible to dynamically select an OpenAPI document's version based on context provided by the user in an HTTP request, for example from a query string.
The version is currently defined in the options as part of registering the endpoint, so it isn't possible to change it other than when registering services, and as the options are registered as a singleton it isn't possible to mutate the options in the scope of an HTTP request to using something like `IPostConfigureOptions` to change its value before the document is written.
https://github.com/dotnet/aspnetcore/blob/02125bdb3eced4a8a562181680581099296b7f72/src/OpenApi/src/Extensions/OpenApiEndpointRouteBuilderExtensions.cs#L75
https://github.com/dotnet/aspnetcore/blob/02125bdb3eced4a8a562181680581099296b7f72/src/OpenApi/src/Extensions/OpenApiEndpointRouteBuilderExtensions.cs#L28
## Proposed API
```diff
public OpenApiOptions
{
+ public Func? OpenApiVersionSelector { get; set; }
}
```
Then change the [endpoint code](https://github.com/dotnet/aspnetcore/blob/02125bdb3eced4a8a562181680581099296b7f72/src/OpenApi/src/Extensions/OpenApiEndpointRouteBuilderExtensions.cs#L52-L76) to use it something like:
```diff
+ var openApiVersion = documentOptions.OpenApiVersionSelector?.Invoke(context) ?? documentOptions.OpenApiVersion;
```
```diff
- await document.SerializeAsync(openApiWriter, documentOptions.OpenApiVersion, context.RequestAborted);
+ await document.SerializeAsync(openApiWriter, openApiVersion, context.RequestAborted);
```
## Usage Examples
```csharp
builder.Services.AddOpenApi("v1", options =>
{
options.OpenApiVersionSelector = (context) =>
{
if (context.Request.Query["version"] is { Count: 1 } version &&
Enum.TryParse(version, out var result))
{
return result;
}
return null;
};
});
```
```http
GET /openapi/v1.json?version=OpenApi3_0
{
"openapi": "3.0.4"
}
```
## Alternative Designs
```diff
public OpenApiOptions
{
+ public Func>? OpenApiVersionSelector { get; set; }
}
```
## Risks
None I can think of.
Contributor guide
Assessment
This issue has not been assessed yet.