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 schema generation for nullable enums produce a null value option #60986

Open
1 task done
eharshosh opened this issue Mar 18, 2025 · 1 comment
Open
1 task done
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-openapi

Comments

@eharshosh
Copy link

eharshosh commented Mar 18, 2025

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When an API method returns a model with a nullable field (or simply returns a nullable enum), the generated enum schema contains 'null' value at the end of the list, which is redundant and actually causes issues with models produced by source code generators (I've noticed an issue with at least this one but it may cause issues with others as well).

{
  "openapi": "3.0.1",
  },
  "components": {
    "schemas": {
      "NullableOfEnumResult": {
        "enum": [
          "A",
          "B",
          null <-- this is unexpected!
        ],
        "nullable": true
      }
    }
  }
}

When returning a nullable enum outside of model, e.g.

app.MapGet("/", () =>  EnumResult.A)
    .Produces<EnumResult?>()

The output is also inconsistent with the output from the scenario above (note the missing "nullable": true):

"NullableOfEnumResult": {
        "enum": [
          "A",
          "B",
          null
        ]
      }

Expected Behavior

I believe that nullable enums should always be modeled like so in all scenarios:

"NullableOfEnumResult": {
  "enum": [
    "A",
    "B"
  ],
  "nullable": true
}

Steps To Reproduce

  1. Create a new WebAPI project (dotnet new webapi)
  2. Add package reference to Microsoft.Extensions.ApiDescription.Server version 9.0.2
  3. Replace the existing Program.cs that came with the template with this code:
using System.Text.Json.Serialization;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
});

var app = builder.Build();
    app.MapOpenApi();

app.MapGet("/", () => new Res(EnumResult.A, "Test"));

app.Run();

record Res(EnumResult? Result, string SomeValue);
enum EnumResult
{
    A,
    B
}
  1. Build and examine the generated JSON schema

For the other scenario (where the enum is not encapsulated within another model) use the following code:

using System.Text.Json.Serialization;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
});

var app = builder.Build();
    app.MapOpenApi();

app.MapGet("/", () => EnumResult.A)
    .Produces<EnumResult?>();

app.Run();

enum EnumResult
{
    A,
    B
}

Exceptions (if any)

No response

.NET Version

9.0.200

Anything else?

No response

@martincostello martincostello added feature-openapi area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc and removed area-web-frameworks labels Mar 18, 2025
@eharshosh
Copy link
Author

B.T.W. I worked around this issue by registering a custom schema transformer:

public class EnumNullValueTransformer : IOpenApiSchemaTransformer
{
    public Task TransformAsync(OpenApiSchema schema, OpenApiSchemaTransformerContext context,
        CancellationToken cancellationToken)
    {
        if (schema.Enum is [.., OpenApiString { Value: null }])
        {
            schema.Enum.RemoveAt(schema.Enum.Count - 1);
            schema.Nullable = true;
        }

        return Task.CompletedTask;
    }
}

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 feature-openapi
Projects
None yet
Development

No branches or pull requests

2 participants