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

Nullability gets ignored for return types and dictionary values #2680

Closed
kpko opened this issue Jul 10, 2023 · 4 comments
Closed

Nullability gets ignored for return types and dictionary values #2680

kpko opened this issue Jul 10, 2023 · 4 comments

Comments

@kpko
Copy link

kpko commented Jul 10, 2023

I have two API methods like this in a fresh ASP.NET Core Web API project using .NET 7 and Swashbuckle.AspNetCore v6.5.0

// Example with nullable dictionary value and return type
app.MapPost("nullable-test", (Dictionary<string, object?> parameters) => "hello")
    .Produces<string?>();

// Example with required dictionary value and return type
app.MapPost("non-nullable-test", (Dictionary<string, object> parameters) => "hello")
    .Produces<string>();

Nullable is enabled in my project, but nullability settings seem to get ignored when the OpenAPI document is generated. Both definitions are exactly the same.

{
  "openapi": "3.0.1",
  "info": {
    "title": "WebApplication3",
    "version": "1.0"
  },
  "paths": {
    "/nullable-test": {
      "post": {
        "tags": [
          "WebApplication3"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": { }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/non-nullable-test": {
      "post": {
        "tags": [
          "WebApplication3"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": { }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": { }
}

Is there anything I must enable to support nullable reference types in return types and parameters? It seems to work in models once I wrap the return/request type in classes.

Thanks!

@vancodocton
Copy link

@kpko, you can add it to swaggergen options. Hope can help you

builder.Services.AddSwaggerGen(c =>
{
    c.SupportNonNullableReferenceTypes();
};

@kpko
Copy link
Author

kpko commented Jul 12, 2023

Hi, I tried enabling this option but this results in the same schema.

builder.Services.AddSwaggerGen(c =>
{
    c.SupportNonNullableReferenceTypes();
    c.UseAllOfToExtendReferenceSchemas();
});

It all seems to work if I try the same thing as in my first example in a model object.

// With model object
app.MapPost("model-object-nullable-test", (Test parameters) => "hello")
    .Produces<Test>();

public class Test
{
    public Dictionary<string, object> NonNullableObjectDict { get; set; } = new();
    public Dictionary<string, object?> NullableObjectDict { get; set; } = new();
    public string NonNullableString { get; set; } = string.Empty;
    public string? NullableString { get; set; }
}

This results in the expected schema.

{
  "openapi": "3.0.1",
  "info": {
    "title": "WebApplication3",
    "version": "1.0"
  },
  "paths": {
    "/model-object-nullable-test": {
      "post": {
        "tags": [
          "WebApplication3"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Test"
                  }
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Test"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Test": {
        "type": "object",
        "properties": {
          "nonNullableObjectDict": {
            "type": "object",
            "additionalProperties": { }
          },
          "nullableObjectDict": {
            "type": "object",
            "additionalProperties": {
              "nullable": true
            }
          },
          "nonNullableString": {
            "type": "string"
          },
          "nullableString": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      }
    }
  }
}

But somehow, once I use the types like Dictionary<string, object?> as the body or the return type, nullability gets weird like in my first example. It seems like there is a different nullability logic involved when comparing the handling of return/parameter types and model classes.

@Havunen
Copy link

Havunen commented Feb 18, 2024

This might be fixed in DotSwashbuckle, can you test using it please.
https://github.com/Havunen/DotSwashbuckle
https://www.nuget.org/packages/DotSwashbuckle.AspNetCore

@martincostello
Copy link
Collaborator

To make issue tracking a bit less overwhelming for the new maintainers (see #2778), I've created a new tracking issue to roll-up various nullability issues here: #2793.

We'll refer back to this issue from there and include it as part of resolving that issue, but I'm going to close this one to help prune the backlog.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants