dotnet / dotnet/aspnetcore

Add property to OpenApiOptions to allow dynamic OpenAPI version selection

Open
#62,984 3 comments 3 reactions 1 assignee Claimed by @Youssef1313 View on GitHub
api-proposal api-suggestion area-minimal feature-openapi
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.