Skip to content

Minimal API Group with OpenAPI and Return Type of Result<TResult> creates incorrect OpenAPI document. #57876

@MarkTallentire

Description

@MarkTallentire

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I have a simple API that uses the new OpenAPI document generation and Minimal APIs that utilize groups functionality.

When using the following code, i expect OpenAPI to generate a document with the available return types of Created and BadRequest.

However I get Ok, Created and BadRequest and it also produces some weird return model types

I also see the following exception in my console.

System.ArgumentException: An item with the same key has already been added. Key: OpenApiSchemaKey { Type = Microsoft.AspNetCore.Http.HttpResults.Results2[Microsoft.AspNetCore.Http.HttpResults.Created1[Api.Features.Accounts.DTOs.CreateAccountResponse],Microsoft.AspNetCore.Http.HttpResults.BadRequest1[FluentValidation.Results.ValidationResult]], ParameterInfo = }
`

using Api.Features.Accounts.DTOs;
using Api.Features.Accounts.Services;
using Api.Features.Accounts.Validators;
using Domain;
using FluentValidation.Results;
using Microsoft.AspNetCore.Http.HttpResults;

namespace Api.Features.Accounts.Endpoints
{
    public static class AccountsEndpoints
    {
        public static RouteGroupBuilder MapAccountsEndpoints(this RouteGroupBuilder group)
        {
            group.MapPost("/", CreateAccount)
                .AllowAnonymous();

            return group;
        }

        public static async Task<Results<Created<CreateAccountResponse>, BadRequest<ValidationResult>>> CreateAccount(CreateAccountRequest accountRequest, AccountService accountService)
        {
            var validator = new CreateAccountRequestValidator();
            var validationResult = await validator.ValidateAsync(accountRequest);

            if (!validationResult.IsValid)
            {
                return TypedResults.BadRequest<ValidationResult>(validationResult);
            }
            
            var account = await accountService.CreateAccount(accountRequest.Username);

            if (account == null)
            {
                validationResult.Errors.Add(new ValidationFailure(nameof(accountRequest.Username), "Username already exists"));
                return TypedResults.BadRequest<ValidationResult>(validationResult);
            }

            return TypedResults.Created<CreateAccountResponse>(new Uri("https://google.com"), new CreateAccountResponse(account.ApiKey));
        }
    }
}
builder.Services.AddOpenApi();
if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.MapScalarApiReference();
}
app.MapGroup("accounts")
    .MapAccountsEndpoints();

Produces:

image

Expected Behavior

To show only Created(201) and BadRequest(400) as available return types and only ValidationResult and CreateAccountResponse as return models.

Steps To Reproduce

Use code above in a new .net9 project and run

Exceptions (if any)

System.ArgumentException: An item with the same key has already been added. Key: OpenApiSchemaKey { Type = Microsoft.AspNetCore.Http.HttpResults.Results2[Microsoft.AspNetCore.Http.HttpResults.Created1[Api.Features.Accounts.DTOs.CreateAccountResponse],Microsoft.AspNetCore.Http.HttpResults.BadRequest1[FluentValidation.Results.ValidationResult]], ParameterInfo = }
`

.NET Version

9.0 preview

Anything else?

I have also attempted to use .Produces() to explicitly define the return types but have the same issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs: Attention 👋This issue needs the attention of a contributor, typically because the OP has provided an update.area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-openapi

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions