Search code examples
c#.netasp.net-coreopenapi

Microsoft.AspNetCore.OpenAPI generates document with schema $refs to previous properties of same type instead of the base schema itself


Given the following class:

public record Response
{
    public ImmutableList<TypeA>? Completes { get; init; } = null;
    public ImmutableList<TypeA>? Incompletes { get; init; } = null;

    .... // rest of class here
}

The package Microsoft.AspNetCore.OpenApi will generate the following OpenAPI spec file:

"Response": {
    "type": "object",
    "properties": {
        "Completes": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/TypeA"
            },
            "nullable": true
        },
        "Incompletes": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/#/properties/Completes/items"
            },
            "nullable": true
        }
    }

The path notation for $ref of "Incompletes" is not valid with the "#" token in the middle of the path, for the API gateway tools I use. Instead, I would like it to just refer to the actual schema, instead of a previous property of the same type, i.e:

"Response": {
    "type": "object",
    "properties": {
        "Completes": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/TypeA"
            },
            "nullable": true
        },
        "Incompletes": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/TypeA"
            },
            "nullable": true
        }
    }

How can this be achieved with the Microsoft.AspNetCore.OpenApi package?

In my Startup.cs, I simply added the following line:

services.AddOpenApi(ConfigureApiGen);

ConfgureApiGen does some simple things like setting document names and so forth using a document transformer.


Solution

  • As far as I can see this is a known issue which should be fixed in the upcoming .NET 9 release. From the comment by captainsafia @github:

    this bug has been fixed in .NET 10 and back-ported to .NET 9. You'll find it in the next servicing release for .NET 9.

    Why did this bug happen? The crux of the issue comes from the incompatibility between schemas generated by System.Text.Json, which comply strictly with the JSON Schema specification, and those expected by the OpenAPI.NET package which are a superset of JSON Schema. STJ uses relative references to capture recursive or duplicate type references. OpenAPI.NET does not recognize these as equivalent which results in duplicate schemas.

    In .NET 9, we fix this by introducing logic to our custom comparers to treat relative references as equivalent to any generated type.

    In .NET 10, we're upgrading to the new version of the OpenAPI.NET package which adds in built-in support for being able to resolve these relative references and detect "loop-backs" in the schema model.

    I'll keep this issue open until the next .NET 9 servicing release ships. In the meantime, happy to answer any questions about the issue.

    Which should be released soon:

    Patches are released on the second Tuesday of a month to align with Microsoft's Update Tuesday, so the earliest would be 11th February.

    As of now you can "revert" to the Swashbuckle or try using NSwag

    Another issue @github