dotnet / dotnet/aspnetcore

Automatically create OpenApiParameters when using BindAsync in Minimal API

Open
#51,218 10 comments 3 reactions 0 assignees View on GitHub
area-minimal feature-minimal-actions feature-openapi
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 10h
Merged PRs (30d)
281

Description

### Is there an existing issue for this?

- [X] I have searched the existing issues

### Is your feature request related to a problem? Please describe the problem.

I'm trying to migrate my controllers-based project to .NET 7 minimal API.
In the old project, I have multiple custom value providers (FromClaim, FromHeaderPart, etc).

In minimal API we can have custom model binding using [BindAsync](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/parameter-binding?view=aspnetcore-7.0#bindasync), but when using this approach we don't get any params in SwaggerUI.

To display parameters we must add this code:
```C#
.WithOpenApi(operation =>
{
operation.Parameters.Add(new OpenApiParameter
{
Name = "sortBy",
Schema = new OpenApiSchema
{
Type = "string",
Default = new OpenApiString("")
},
Description = "Sort by",
Required = false,
In = ParameterLocation.Query
});

operation.Parameters.Add(new OpenApiParameter
{
Name = "sortDir",
Schema = new OpenApiSchema
{
Type = "string",
Default = new OpenApiString("asc"),
Enum = new List
{
new OpenApiString("asc"),
new OpenApiString("desc")
}
},
Description = "Sort direction",
Required = true,
In = ParameterLocation.Query
});

operation.Parameters.Add(new OpenApiParameter
{
Name = "page",
Schema = new OpenApiSchema
{
Type = "integer",
Default = new OpenApiInteger(1)
},
Description = "Page number",
Required = true,
In = ParameterLocation.Query
});

return operation;

});
```

Ideally, this should be done automatically based on attributes

### Describe the solution you'd like

Ideally, we should be able to annotate properties that are binding from known places with attributes.
So the above `WithOpenApi` could be omitted and a valid list of parameters would be created automatically.
We could use attributes from `Microsoft.AspNetCore.Mvc` or create new ones if needed.

```C#
public class MyCustomParameters
{
[FromQuery]
public string? SortBy { get; init; }

[FromQuery]
[Required]
public SortDirection Sort { get; init; }

[FromQuery]
[Required]
public int CurrentPage { get; init; } = 1;

public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter)
{
const string sortByKey = "sortBy";
const string sortDirectionKey = "sortDir";
const string currentPageKey = "page";

Enum.TryParse(context.Request.Query[sortDirectionKey],ignoreCase: true, out var sortDirection);
int.TryParse(context.Request.Query[currentPageKey], out var page);
page = page == 0 ? 1 : page;

var result = new MyCustomParameters
{
SortBy = context.Request.Query[sortByKey],
Sort = sortDirection,
CurrentPage = page
};

return ValueTask.FromResult(result);
}

public enum SortDirection
{
Asc,
Desc
}
}
```

### Additional context

My main idea is to remove repetitive code that must be added for each endpoint that is using custom binding.

Contributor guide

Open the contributing guide

Research direction

Start by tracing Minimal API BindAsync parameter binding and the WithOpenApi customization shown in the issue. Compare how attributes such as FromQuery and Required could describe generated OpenAPI parameters. Done means BindAsync-bound properties produce the expected query parameters, schemas, defaults, enum values, descriptions, and required flags without per-endpoint WithOpenApi code.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, openapi
Domain
api, backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.