Swashbuckle.AspNetCore icon indicating copy to clipboard operation
Swashbuckle.AspNetCore copied to clipboard

Nested complex types not documented

Open wim07101993 opened this issue 3 years ago • 8 comments

Problem

I have a POST method:

public async Task<IActionResult> Post([FromBody] Person newMember)

With the Person model being:

public class Person {
    /// <summary>The name of the new member.</summary>
    public string Name { get; set; }

    /// <summary>The pet the new member likes the most.</summary>
    public Pet FavouritePet { get; set; }

    /// <summary>The pet the new member likes the least.</summary>
    public Pet LeastFavouritePet { get; set; }
}

Here the 'pet'-properties are not documented in the open-api spec. There is only a $ref to another schema but no description to show what the properties are. In contrast this description is available for non-complex members like eg Name.

What I would like to see

Documentation for complex types like nested objects.

wim07101993 avatar Mar 21 '22 13:03 wim07101993

Dup of #1303. Long story short - enable the UseAllOfToExtendReferenceSchemas setting.

domaindrivendev avatar Mar 23 '22 20:03 domaindrivendev

@domaindrivendev that is not really the solution I was looking for.

By using the UseAllOfToExtendReferenceSchemas, the schema results in:

"Person": {
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "The name of the new member."
    },
    "favouritePet ": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Pet"
        }
      ],
      "description": "The documentation of the a Pet."
    },
    "leastFavouritePet ": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Pet"
        }
      ],
      "description": "The documentation of the a Pet."
    },
  },
  "additionalProperties": false
},

Where I would expect it to be:

"Person": {
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "The name of the new member."
    },
    "favouritePet ": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Pet"
        }
      ],
      "description": "The pet the new member likes the most."
    },
    "leastFavouritePet ": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Pet"
        }
      ],
      "description": "The pet the new member likes the least."
    },
  },
  "additionalProperties": false
},

The description of the nested object is taken from the class, not the properties.

wim07101993 avatar Mar 24 '22 11:03 wim07101993

Can this issue be reopened?

wim07101993 avatar Apr 07 '22 07:04 wim07101993

Hi! I second this issue. I'm looking for the way to have the property's XML documentation in the description field.

starteleport avatar Jul 19 '23 07:07 starteleport

I am running into a similar issue with the above, because if I have a property that is marked as deprecated using ObsoleteAttribute, but the property is a referenced complex type and not something simple like a string or a date, it does not show up as deprecated, possibly because it is using the documentation (and attributes) for the referenced type and ignoring the ones for the actual property.
~I will throw together a simple example and create a separate issue. Stay tuned.~ Issue #2760

mike-loux-planview avatar Jan 22 '24 18:01 mike-loux-planview

This issue is stale because it has been open for 60 days with no activity. It will be automatically closed in 14 days if no further updates are made.

github-actions[bot] avatar Apr 27 '24 01:04 github-actions[bot]

I'm sure there was another issue or PR related to this recently, but I can't find it...

martincostello avatar Apr 27 '24 15:04 martincostello

This issue is stale because it has been open for 60 days with no activity. It will be automatically closed in 14 days if no further updates are made.

github-actions[bot] avatar Jun 27 '24 01:06 github-actions[bot]

This issue is stale because it has been open for 60 days with no activity. It will be automatically closed in 14 days if no further updates are made.

github-actions[bot] avatar Sep 04 '24 01:09 github-actions[bot]

Bump to prevent staleness

k290 avatar Sep 04 '24 09:09 k290

@wim07101993 I have just tested with this code:

using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
	c.IncludeXmlComments(
	  Path.Combine(AppContext.BaseDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"),
	  true);
	c.UseAllOfToExtendReferenceSchemas();
	c.SwaggerDoc("v1", new OpenApiInfo { Title = "Test API", Version = "1" });
});
//builder.Services.AddSwaggerGenNewtonsoftSupport();

var app = builder.Build();

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

app.UseAuthorization();

app.MapControllers();

app.Run();

public class TestController : ControllerBase
{
	[HttpPost("Person")]
	public async Task<IActionResult> Post([FromBody] Person newMember) => NotFound();

}
public class Person
{
	/// <summary>The name of the new member.</summary>
	public string Name { get; set; }

	/// <summary>The pet the new member likes the most.</summary>
	public Pet FavouritePet { get; set; }

	/// <summary>The pet the new member likes the least.</summary>
	public Pet LeastFavouritePet { get; set; }
}
/// <summary>
/// Summary for Pet
/// </summary>
public class Pet
{
	public string Name { get; set; }
}

And with SwashBuckle latest version and also with version 6.0.0 and both of them produced the same OpenApi document(The only difference is the Description of the response 200 from Success to OK):

{
  "openapi": "3.0.1",
  "info": {
    "title": "Test API",
    "version": "1"
  },
  "paths": {
    "/Person": {
      "post": {
        "tags": [
          "Test"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Person"
                  }
                ]
              }
            },
            "text/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Person"
                  }
                ]
              }
            },
            "application/*+json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Person"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Person": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the new member.",
            "nullable": true
          },
          "favouritePet": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Pet"
              }
            ],
            "description": "The pet the new member likes the most.",
            "nullable": true
          },
          "leastFavouritePet": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Pet"
              }
            ],
            "description": "The pet the new member likes the least.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "Pet": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Summary for Pet"
      }
    }
  }
}

I have also tested switching from dotnet6 to dotnet8, and both of them worked. Could you please see if this issue persist?

jgarciadelanoceda avatar Sep 08 '24 15:09 jgarciadelanoceda

Issue seems to be solved. Thanks

wim07101993 avatar Sep 09 '24 12:09 wim07101993