Nswag: XML Comments make property invisible in swagger UI example json

Created on 28 Jan 2020  路  2Comments  路  Source: RicoSuter/NSwag

Hello,

Using NSwag.AspNetCore 13.2.2, given an API controller that returns the following response model

    public class Hero
    {
        public string? FirstName { get; set; }
        public string? LastName { get; set; }
        public string? Alias { get; set; }
        public LoveInterest LoveInterest { get; set; } = new LoveInterest();
    }

    public class LoveInterest
    {
        public string? FirstName { get; set; }
        public string? LastName { get; set; }
    }

Will generate the following schema in the Open API doc

{
    "Hero": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
            "firstName": {
                "type": "string",
                "nullable": true
            },
            "lastName": {
                "type": "string",
                "nullable": true
            },
            "alias": {
                "type": "string",
                "nullable": true
            },
            "loveInterest": {
                "$ref": "#/components/schemas/LoveInterest"
            }
        }
    },
    "LoveInterest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
            "firstName": {
                "type": "string",
                "nullable": true
            },
            "lastName": {
                "type": "string",
                "nullable": true
            }
        }
    }
}

This renders fine in the Swagger UI. Specifically, the response example JSON includes the loveInterest property.

However, if I change the model to include an XML comment on the LoveInterest property:

        /// <summary>
        /// The love interest
        /// </summary>
        public LoveInterest LoveInterest { get; set; } = new LoveInterest();

Then the Open API doc includes this schema

{
    "Hero": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
            "firstName": {
                "type": "string",
                "nullable": true
            },
            "lastName": {
                "type": "string",
                "nullable": true
            },
            "alias": {
                "type": "string",
                "nullable": true
            },
            "loveInterest": {
                "description": "The love interest",
                "oneOf": [
                    {
                        "$ref": "#/components/schemas/LoveInterest"
                    }
                ]
            }
        }
    },
    "LoveInterest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
            "firstName": {
                "type": "string",
                "nullable": true
            },
            "lastName": {
                "type": "string",
                "nullable": true
            }
        }
    }
}

And in this case, the Swagger UI will not render the loveInterest property in the response example JSON. This means, given a very basic model, adding an XML comment causes the property to be invisible in the Swagger UI examples.

To Summarize:

Works as expected

When the schema is generated as

            "loveInterest": {
                "$ref": "#/components/schemas/LoveInterest"
            }

Property is missing from example

when the schema is generated as

            "loveInterest": {
                "description": "The love interest",
                "oneOf": [
                    {
                        "$ref": "#/components/schemas/LoveInterest"
                    }
                ]
            }

This seems similar to #2071, in which case it was the presense of the nullable attribute which triggered the generation of oneOf, however, it seems other attributes (in this case description) will also change from a simple $ref to oneOf

This seems quite problematic. If Swagger UI has issues with oneOf, is there a way it can be avoided in this scenario?

Most helpful comment

We experience the same problem in our nested DTOs

public class Container
{
    [Required]
    public A A {get;set;}       
}

public class A
{
    /// <summary>
    /// This results in the problem
    /// </summary>
    [Required]
    public B BDoesNotWork { get; set; } // Note: examples set in B it self would now work

    [Required]
    public B BDoesWork { get; set; }

    /// <summary>
    /// This works
    /// </summary>
    /// <example>
    /// { "Id": "1" }
    /// </example>
    [Required]
    public B BWithCustomSample { get; set; } //Note: this generates an example, but the example can be anything...

    [Required]
    public string Name { get; set; }
}
public class B
{
    /// <summary>
    /// THe Name
    /// </summary>
    /// <example>
    /// Some Name
    /// </example>
    ///
    [Required]
    public string Name { get; set; }
}

Results into the following:

 "A": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "bDoesNotWork",
          "bDoesWork",
          "bWithCustomSample",
          "name"
        ],
        "properties": {
          "bDoesNotWork": {
            "description": "This results in the problem",
            "oneOf": [
              {
                "$ref": "#/components/schemas/B"
              }
            ]
          },
          "bDoesWork": {
            "$ref": "#/components/schemas/B"
          },
          "bWithCustomSample": {
            "description": "This works",
            "example": {
              "Id": "1"
            },
            "oneOf": [
              {
                "$ref": "#/components/schemas/B"
              }
            ]
          },
          "name": {
            "type": "string",
            "minLength": 1
          }
        }
      },
      "B": {
        "type": "object",
        "description": " ",
        "additionalProperties": false,
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "THe Name",
            "minLength": 1,
            "example": "Some Name"
          }
        }
      }

Both the custom sample and the one with just a descriptive name for the field generate as one-off.
This means I can have either incomplete swagger docs, or incomplete documentation of my DTOs

All 2 comments

We experience the same problem in our nested DTOs

public class Container
{
    [Required]
    public A A {get;set;}       
}

public class A
{
    /// <summary>
    /// This results in the problem
    /// </summary>
    [Required]
    public B BDoesNotWork { get; set; } // Note: examples set in B it self would now work

    [Required]
    public B BDoesWork { get; set; }

    /// <summary>
    /// This works
    /// </summary>
    /// <example>
    /// { "Id": "1" }
    /// </example>
    [Required]
    public B BWithCustomSample { get; set; } //Note: this generates an example, but the example can be anything...

    [Required]
    public string Name { get; set; }
}
public class B
{
    /// <summary>
    /// THe Name
    /// </summary>
    /// <example>
    /// Some Name
    /// </example>
    ///
    [Required]
    public string Name { get; set; }
}

Results into the following:

 "A": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "bDoesNotWork",
          "bDoesWork",
          "bWithCustomSample",
          "name"
        ],
        "properties": {
          "bDoesNotWork": {
            "description": "This results in the problem",
            "oneOf": [
              {
                "$ref": "#/components/schemas/B"
              }
            ]
          },
          "bDoesWork": {
            "$ref": "#/components/schemas/B"
          },
          "bWithCustomSample": {
            "description": "This works",
            "example": {
              "Id": "1"
            },
            "oneOf": [
              {
                "$ref": "#/components/schemas/B"
              }
            ]
          },
          "name": {
            "type": "string",
            "minLength": 1
          }
        }
      },
      "B": {
        "type": "object",
        "description": " ",
        "additionalProperties": false,
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "THe Name",
            "minLength": 1,
            "example": "Some Name"
          }
        }
      }

Both the custom sample and the one with just a descriptive name for the field generate as one-off.
This means I can have either incomplete swagger docs, or incomplete documentation of my DTOs

I think swagger ui cannot resolve the oneof reference, so maybe you need to set AllowReferencesWithProperties to true

https://apimundo.com/organizations/nuget-org/nuget-feeds/public/packages/NJsonSchema/versions/latest?tab=types&type=NJsonSchema.Generation.JsonSchemaGeneratorSettings

Was this page helpful?
0 / 5 - 0 ratings