Skip to content

Unintuitive/incorrect behaviour from use of WithOpenApi() #41623

Closed
@martincostello

Description

@martincostello

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Using the new WithOpenApi() method with Minimal APIs in .NET 7 preview 4 in conjunction with Swashbuckle.AspNetCore produces unintuitive results in the generated swagger.json file.

If either WithOpenApi() overload is used, the metadata that would be present without it is lost, some information is incorrectly added, and information that doesn't work at all without it (see #40753) does render.

Below is the swagger.json generated by Swashbuckle.AspNetCore using the repro application included later in this issue.

For resource /a:

  1. The response is correctly described as HTTP 200 returning MyModel and has a description
  2. There is no request body
  3. The summary and description are missing

For resources /b and /c:

  1. The response is described as an HTTP 200, but is just described as an object with no description
  2. The request has gained an empty request body
  3. The summary and description are present

Neither resource is 100% correct in its description.

swagger.json
{
  "openapi": "3.0.1",
  "info": {
    "title": "API",
    "version": "v1"
  },
  "paths": {
    "/a": {
      "get": {
        "tags": [
          "NoProblemDetailsOpenApi"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyModel"
                }
              }
            }
          }
        }
      }
    },
    "/b": {
      "get": {
        "tags": [
          "NoProblemDetailsOpenApi"
        ],
        "summary": "Say hi",
        "description": "Says hi to you",
        "requestBody": {
          "content": { }
        },
        "responses": {
          "200": {
            "description": null,
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/c": {
      "get": {
        "tags": [
          "NoProblemDetailsOpenApi"
        ],
        "summary": "Say bonjour",
        "description": "Says bonjour to you",
        "requestBody": {
          "content": { }
        },
        "responses": {
          "200": {
            "description": null,
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "MyModel": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      }
    }
  }
}

Expected Behavior

WithOpenApi() provides the ability for the user to extend the operations generated by default (or allows them to be completely replaced) without losing any of those conventions.

I would expect that the object passed to WithOpenApi() would contain the same detail as if it had not been used on the endpoint at all.

In the example given, this would mean that:

  1. The response is described as MyModel with a description
  2. There is no request body
  3. The summary and description for the operation are present

Steps To Reproduce

Program.cs

using Microsoft.AspNetCore.OpenApi;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new() { Title = "API", Version = "v1" });
});

var app = builder.Build();

// Endpoint has response, but no summary or description
app.MapGet("/a", () => TypedResults.Ok(new MyModel("Hello world!")))
   .WithSummary("Say hello")
   .WithDescription("Says hello to you");

// Endpoint has summary and description, but a non-specific response and gains a body
app.MapGet("/b", () => TypedResults.Ok(new MyModel("Hi world!")))
   .WithSummary("Say hi")
   .WithDescription("Says hi to you")
   .WithOpenApi();

// Endpoint has summary and description, but a non-specific response and gains a body
app.MapGet("/c", () => TypedResults.Ok(new MyModel("Bonjour world!")))
   .WithOpenApi(operation =>
   {
       operation.Summary = "Say bonjour";
       operation.Description = "Says bonjour to you";
       return operation;
   });

app.UseSwagger();

app.Run();

public record MyModel(string Text);

Project.csproj

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.0-preview.4.22251.1" /> 
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1" />
  </ItemGroup>
</Project>

Exceptions (if any)

No response

.NET Version

7.0.100-preview.4.22252.9

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions