Swashbuckle.aspnetcore: Default value not working for enum's

Created on 29 May 2019  路  17Comments  路  Source: domaindrivendev/Swashbuckle.AspNetCore

Default value is not working for enums, e.g.:

```c#
public ActionResult> Get(
[FromQuery, BindRequired] string q,
[FromQuery]int page = 1,
[FromQuery]int pageSize = 20,
[FromQuery]AutocompleteMatchType matchType = AutocompleteMatchType.BeginFirst)

then in the generated JSON:

```json
"parameters": [
  {
    "name": "q",
    "in": "query",
    "required": true,
    "schema": {
      "type": "string"
    }
  },
  {
    "name": "page",
    "in": "query",
    "schema": {
      "type": "integer",
      "format": "int32",
      "default": 1
    }
  },
  {
    "name": "pageSize",
    "in": "query",
    "schema": {
      "type": "integer",
      "format": "int32",
      "default": 20
    }
  },
  {
    "name": "matchType",
    "in": "query",
    "schema": {
      "enum": [
        "begin",
        "any",
        "beginFirst"
      ],
      "type": "string"
    }
  }
]

Noting that there is no default value in the JSON for the enum, even though one exists.

This seems to be down to the fact that OpenApiPrimitiveFactory.FactoryMethodMap does not contain any way to create an OpenApiPrimitive<T> for an enum, therefore the call to schema.Default = OpenApiPrimitiveFactory.CreateFrom(parameterInfo.DefaultValue); returns and sets a null value within the method SwaggerGenerator.GenerateParameter(...) making it look from then on as if there was no default value (even though parameterInfo.DefaultValue with the correct default value does exist, and is passed in to that call).

I'd be interested to work on this if it's considered useful. I'm not quite sure if it is even possible to generate an OpenApiPrimitive<T> where T is an enum type? If so, then some reflection-based code added in to OpenApiPrimitiveFactory.CreateFrom(...) to deal with that sounds like it might be the way to go? (Noting that the default value for an enum depends on whether the values for the enum are being output as string or int, so it would be important to display the default value in the correct format as well.)

Most helpful comment

@michaelakin, @MikeBeaton - I don't have a date for the next release at the moment. There's a couple of changes in master that MAY be breaking for certain use cases, and so the next release will be a major version increment. As such, I want to include a couple of other potentially breaking changes and don't have a good sense of when they will be done. I'm anticipating weeks rather than months, but you never know with OSS - the stuff that actually pays the bills always takes precedence.

With that said, you can pull down preview Nugets of the latest master at any point from myget.org. I would encourage you to do this if you need the changes sooner:
https://myget.org/feed/domaindrivendev/package/nuget/Swashbuckle.AspNetCore

All 17 comments

I got a bit further with this and had my own working version with support for enum defaults on parameters and properties, and supporting tests. It was based off c887fbb 7 Feb 2019, but then I realised quite a lot has changed.

As of the current master, it seems like:

  • Default enum value is now set for parameters and properties (for enum serialized as string or int) (but is not correctly camel-cased for enum serialized as string, when camel-casing is set in options or StringEnumConverter)
  • There no longer seems to be support for renaming enum members with EnumMember, which there was in the earlier version

In order to fully correctly support enum defaults (given the possibility of arbitrary enum member name mapping) then either the default value has to be available within PrimitiveSchemaGenerator.GenerateEnumSchema, where all the required mapping is known and the default value can be mapped and set directly in the schema at that time, or else the correct settings for camel case (and for EnumMember name mapping, if it is to be supported?) have to be re-derived at the point where the default is going to be set. The former is how I ended up doing it, passing down a new Enum defaultEnumValue parameter (just for enum defaults...) through the chain, starting in either SwaggerGenerator.GenerateParameter or SchemaRegistry.CreatePropertyOpenApiSchema.

I've done a PR for just the camel-case fix, since that seems to be the only issue, as long as enum member renaming is disabled, and since it's useful to me right now to have my enum defaults shown correctly in my swagger UI! 馃槉

+1 On this . My team has run into the same issue.

Has anyone figured out what to do on this? We are converting to .net Core 3.1 and we have run across this and have not yet found a work around.

@michaelakin
My workaround is to use UseInlineDefinitionsForEnums

services.AddSwaggerGen(options =>
{
    options.UseInlineDefinitionsForEnums();

@michaelakin
My workaround is to use UseInlineDefinitionsForEnums

services.AddSwaggerGen(options =>
{
    options.UseInlineDefinitionsForEnums();

If I use this method even if I have StringEnumConverter added to the Json serializer configuration, my API params now show just the numbers for the enum types instead of the names. The names have meaning to the API consumer, but the number values alone do not. I really need a default to be specified but with the enum being represented by its names not the number values.

Thanks. That helped get us back to where we were. Unfortunately it doesn鈥檛 seem to handle the enums very elegantly and hope that will be improved.

Wrt to current version 5.6.3 UseInlineDefinitionsForEnums() brings back the default value, which is great, but it does not respect mappings such as camel-casing.

Here's a live example:

image

{
  "name": "matchType",
  "in": "query",
  "schema": {
    "enum": [
      "begin",
      "any",
      "beginFirst"
    ],
    "type": "string",
    "description": "Allowed match types",
    "default": "BeginFirst"
  }
}

The available values have been mapped (camel-cased) correctly, but the default value remains in its unmapped form.

@Zoidborg7 If you use the latest version of Swashbuckle.AspNetCore from NuGet - which I found slotted in place instead of v4 very easily - and apply UseInlineDefinitionsForEnums() then you should see string enum member names in the defaults.

The remaining problem, still in need of a fix, only comes if there is a mapping - e.g. camel casing - between the C# enum member names and the API enum member names: the mapping is still not applied to the string defaults.

In PR #1852 I've tried to implemented a fairly comprehensive fix for this issue (and related issue #1850) in a clean, lightweight, backwards compatible way.

If allows two different, correct ways to support string enum defaults, even if enum member name mappings are applied: it can work with inline enums or with referenced enums using the allOf/$ref support (see the examples in the description of #1852).

+1 On this. I run into the same issue.

I see this is fixed, when will the next release be?

@michaelakin I don't know if it helps, but you know it's relatively easy to clone the current version of the code and link it directly into your VS build, if you are urgently in need of these features? I could expand with slightly more detailed instructions if it's of interest (and not already obvious to you - as it may well be! - that this is an option). (If it is already obvious to you how to do this, just to note that you need to run npm ci manually once in the ReDoc project directory before it will build.)

EDIT: Okay, this is not the best approach (not unless you are actually going to want to edit the Swashbuckle.AspNetCore source code). @domaindrivendev points out the correct approach immediately below. Sorry!

@michaelakin, @MikeBeaton - I don't have a date for the next release at the moment. There's a couple of changes in master that MAY be breaking for certain use cases, and so the next release will be a major version increment. As such, I want to include a couple of other potentially breaking changes and don't have a good sense of when they will be done. I'm anticipating weeks rather than months, but you never know with OSS - the stuff that actually pays the bills always takes precedence.

With that said, you can pull down preview Nugets of the latest master at any point from myget.org. I would encourage you to do this if you need the changes sooner:
https://myget.org/feed/domaindrivendev/package/nuget/Swashbuckle.AspNetCore

Thanks @MikeBeaton and @domaindrivendev We may try that. It would be great to see how this code resolved the enum issues and we look forward to trying it.

@domaindrivendev Would you be amenable to me opening a PR with a brief update to README.md about how to configure enum defaults?

Something like:


Due to limitations in the OpenAPI specification itself, default values cannot be specified for any parameter which has a referenced type. Enums are referenced types by default in Swashbuckle.AspNetCore, which means that default values for enum parameters will silently disappear with the default settings. However there are two configuration options you can choose, either of which will modify the output OpenAPI structure slightly, and both of which are compatible with enum default values. So if you use default values for enum parameters in your API, you should configure one or other of:

services.AddSwaggerGen(c =>
{
    // ...

    c.UseInlineDefinitionsForEnums();
})

or

services.AddSwaggerGen(c =>
{
    // ...

    c.UseAllOfToExtendReferenceSchemas();
})
Was this page helpful?
0 / 5 - 0 ratings