dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.56k stars 10.05k forks source link

OpenAPI Ref invalid when objects cycles #58915

Open Chrille79 opened 1 week ago

Chrille79 commented 1 week ago

Is there an existing issue for this?

Describe the bug

If you have an model with types as following Person->Address->Person The referens get invalid and doesnt point to a type in components

"$ref": "#/components/schemas/#/properties/myAddress/properties/mailOfficer"

Expected Behavior

$refs must reference a valid location in the document

Steps To Reproduce

Example application

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();

app.MapGet("/person", () =>
{
    return new Person();
})
.WithName("GetPerson");

app.Run();

public class Person
{
    public string Name { get; set; } = string.Empty;
    public Address MyAddress { get; set; } = new();
    public Address? MyAltAddress { get; set; }
}
public class Address
{
    public string Street { get; set; } = string.Empty;
    public string? City { get; set; }
    public int Number { get; set; }

    public Person? MailOfficer { get; set; } /* Ref error if included */
}

Schema output

{
  "openapi": "3.0.1",
  "info": {
    "title": "ExploringOAPI | v1",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://localhost:7103"
    },
    {
      "url": "http://localhost:5263"
    }
  ],
  "paths": {
    "/person": {
      "get": {
        "tags": [
          "ExploringOAPI"
        ],
        "operationId": "GetPerson",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Person"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Address": {
        "type": "object",
        "properties": {
          "street": {
            "type": "string"
          },
          "city": {
            "type": "string",
            "nullable": true
          },
          "number": {
            "type": "integer",
            "format": "int32"
          },
          "mailOfficer": {
            "$ref": "#/components/schemas/Person2"
          }
        }
      },
      "Address2": {
        "type": "object",
        "properties": {
          "street": {
            "type": "string"
          },
          "city": {
            "type": "string",
            "nullable": true
          },
          "number": {
            "type": "integer",
            "format": "int32"
          },
          "mailOfficer": {
            "$ref": "#/components/schemas/#/properties/myAddress/properties/mailOfficer"
          }
        },
        "nullable": true
      },
      "Person": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "myAddress": {
            "$ref": "#/components/schemas/Address"
          },
          "myAltAddress": {
            "$ref": "#/components/schemas/#/properties/myAddress/properties/mailOfficer/properties/myAltAddress"
          }
        }
      },
      "Person2": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "myAddress": {
            "$ref": "#/components/schemas/#/properties/myAddress"
          },
          "myAltAddress": {
            "$ref": "#/components/schemas/Address2"
          }
        },
        "nullable": true
      }
    }
  },
  "tags": [
    {
      "name": "ExploringOAPI"
    }
  ]
}

Exceptions (if any)

No response

.NET Version

9.0.100

Anything else?

No response

leaHaimovich commented 1 week ago

Use JsonIgnore for Circular Property or Use a Custom Schema Filter (builder.Services.AddSwaggerGen(c => { c.SchemaFilter(); }); )

Chrille79 commented 1 week ago

Use JsonIgnore for Circular Property or Use a Custom Schema Filter (builder.Services.AddSwaggerGen(c => { c.SchemaFilter(); }); )

This is Microsoft.Openapi and the reference in schema are not RFC3986 compliant. To use AddSwaggerGen from swashbuckle is a workaround, but not a fix on the bug

ZeroZipZilch commented 1 week ago

It doesn't even have to cycle. It's enough to reference the same class twice in two different collections.

public class WeatherForecast
{
    // Having "Update" in two lists causes the bug to surface.
    public List<Update> RainUpdates { get; set; }
    public List<Update> HurricaneUpdates { get; set; }
}

public sealed class Update
{
    public DateOnly Date { get; set; }
    public string Message { get; set; }    
}
akamor commented 3 days ago

Hitting same issue without cycles. Likely related to https://github.com/dotnet/aspnetcore/issues/58968.