Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenAPI document generation does not generate correct refs for self-referencing collection properties #58006

Open
1 task done
null-d3v opened this issue Sep 21, 2024 · 1 comment
Assignees
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates feature-openapi
Milestone

Comments

@null-d3v
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Microsoft.AspNetCore.OpenApi will generate an invalid JSON schema when a parameter has a self-reference collection property. This does not seem to occur if the self reference is not a collection.

Using the following as a parameter:

public class Criteria
{
    public IEnumerable<Criteria> SubCriteria { get; set; } = [ ];
}

[FromBody] Criteria criteria

Will result in the JSON schema:

  "components": {
    "schemas": {
      "Criteria": {
        "type": "object",
        "properties": {
          "subCriteria": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/#"
            }
          }
        }
      }
    }
  },

Which has an invalid reference:

Resolver error at components.schemas.Criteria.properties.subCriteria.items.$ref
Could not resolve reference: Could not resolve pointer: /components/schemas/ does not exist in document

This occurs with both minimal APIs and controllers.

Expected Behavior

I would expect the subCriteria items reference to correctly point at #/components/schemas/Criteria.

Steps To Reproduce

Here is a complete self-contained Program.cs which will generate the invalid OpenAPI document:

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi().CacheOutput();

app.MapPost("/item/search", ([FromBody] Criteria criteria) =>
{
    var items = Enumerable
        .Range(1, 5)
        .Select(index =>
            new Item
            {
                Name = index.ToString(),
            })
        .ToArray();
    return items;
})
.WithName("SearchItems")
.WithOpenApi();

app.Run();

public class Item
{
    public string Name { get; set; } = default!;
}

public class Criteria
{
    public IEnumerable<Criteria> SubCriteria { get; set; } = [ ];
}

And the OpenAPI document generated at /openapi/v1.json:

{
  "openapi": "3.0.1",
  "info": {
    "title": "Sample | v1",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "http://localhost:5129"
    }
  ],
  "paths": {
    "/item/search": {
      "post": {
        "tags": [
          "Sample"
        ],
        "operationId": "SearchItems",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Criteria"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Criteria": {
        "type": "object",
        "properties": {
          "subCriteria": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/#"
            }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Sample"
    }
  ]
}

Exceptions (if any)

No response

.NET Version

9.0.100-rc.1.24452.12

Anything else?

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-web-frameworks *DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels label Sep 21, 2024
@captainsafia
Copy link
Member

@null-d3v Thanks for reporting this issue!

I'm hoping to drop a fix for this in the upcoming .NET 9 GA release. Once the change is merged, you can try out the fix in one of our nightly releases of the package. If you're interested in learning how to do that, let me know and I can share instructions.

@captainsafia captainsafia self-assigned this Sep 23, 2024
@captainsafia captainsafia added this to the 9.0.0 milestone Sep 23, 2024
@captainsafia captainsafia added area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc and removed area-web-frameworks *DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels labels Sep 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates feature-openapi
Projects
None yet
Development

No branches or pull requests

3 participants