Swagger UI Web API Documentation Present Enums as Strings

Swagger Swashbuckle Asp.NET Core: show details about every enum is used

we can see only default value and no way to see available list of enum
(names and values). I would like to show it. How to do it?

To display the enums as strings in swagger, you configure the JsonStringEnumConverter, adding the following line in ConfigureServices :

        services.AddControllers().AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));

The output as below:

Sample Image

If you want to display the enums as stings and int values, you could try to create a EnumSchemaFilter to change the schema. code as below:

public class EnumSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (context.Type.IsEnum)
{
model.Enum.Clear();
Enum.GetNames(context.Type)
.ToList()
.ForEach(name => model.Enum.Add(new OpenApiString($"{Convert.ToInt64(Enum.Parse(context.Type, name))} = {name}")));
}
}
}

Configure the SwaggerGen to use above ShemaFilter.

        services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "ToDo API",
Description = "A simple example ASP.NET Core Web API",
TermsOfService = new Uri("https://example.com/terms"),
Contact = new OpenApiContact
{
Name = "Shayne Boyer",
Email = string.Empty,
Url = new Uri("https://twitter.com/spboyer"),
},
License = new OpenApiLicense
{
Name = "Use under LICX",
Url = new Uri("https://example.com/license"),
}
});

c.SchemaFilter<EnumSchemaFilter>();
});

The result like this:

Sample Image

Swagger enum with names

services
.AddControllers()
.AddJsonOptions(options =>
options.SerializerSettings.Converters.Add(new StringEnumConverter()));

Show Enum member friendly name on Swagger dropdown and json

I came up with a hack here. It may not necessarily be the solution for you however if you can make it work then I'm happy I could help.

Ended up changing the enum format to string instead of default dropdown. This way I could send asc/desc values to the api. Swagger accepted the values and didnt throw validation errors. And the converter I wrote on the .net core api was also able to convert them nicely.

c.MapType<SortDirectionType>(() => new Schema { Type = "string", Format = "string" });

In addition to this, you may also want to disable default behavior of asp.net core 2.2 validation that kicks in automatically. Not sure why they chose to set that as default behavior.

services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});

Swagger C# Enum generation - underlying int values do not match the original enum

So these are the two Enum Helpers I'm using. One is used by NSwag (x-enumNames) and the other is used by Azure AutoRest (x-ms-enums)

Finally found the reference for EnumDocumentFilter (https://stackoverflow.com/a/49941775/1910735)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace SwaggerDocsHelpers
{
/// <summary>
/// Add enum value descriptions to Swagger
/// https://stackoverflow.com/a/49941775/1910735
/// </summary>
public class EnumDocumentFilter : IDocumentFilter
{
/// <inheritdoc />
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
// add enum descriptions to result models
foreach (var schemaDictionaryItem in swaggerDoc.Definitions)
{
var schema = schemaDictionaryItem.Value;
foreach (var propertyDictionaryItem in schema.Properties)
{
var property = propertyDictionaryItem.Value;
var propertyEnums = property.Enum;
if (propertyEnums != null && propertyEnums.Count > 0)
{
property.Description += DescribeEnum(propertyEnums);
}
}
}

if (swaggerDoc.Paths.Count <= 0) return;

// add enum descriptions to input parameters
foreach (var pathItem in swaggerDoc.Paths.Values)
{
DescribeEnumParameters(pathItem.Parameters);

// head, patch, options, delete left out
var possibleParameterisedOperations = new List<Operation> { pathItem.Get, pathItem.Post, pathItem.Put };
possibleParameterisedOperations.FindAll(x => x != null)
.ForEach(x => DescribeEnumParameters(x.Parameters));
}
}

private static void DescribeEnumParameters(IList<IParameter> parameters)
{
if (parameters == null) return;

foreach (var param in parameters)
{
if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true)
{
param.Description += DescribeEnum(nbParam.Enum);
}
else if (param.Extensions.ContainsKey("enum") && param.Extensions["enum"] is IList<object> paramEnums &&
paramEnums.Count > 0)
{
param.Description += DescribeEnum(paramEnums);
}
}
}

private static string DescribeEnum(IEnumerable<object> enums)
{
var enumDescriptions = new List<string>();
Type type = null;
foreach (var enumOption in enums)
{
if (type == null) type = enumOption.GetType();
enumDescriptions.Add($"{Convert.ChangeType(enumOption, type.GetEnumUnderlyingType())} = {Enum.GetName(type, enumOption)}");
}

return $"{Environment.NewLine}{string.Join(Environment.NewLine, enumDescriptions)}";
}
}

public class EnumFilter : ISchemaFilter
{
public void Apply(Schema model, SchemaFilterContext context)
{
if (model == null)
throw new ArgumentNullException("model");

if (context == null)
throw new ArgumentNullException("context");

if (context.SystemType.IsEnum)
{

var enumUnderlyingType = context.SystemType.GetEnumUnderlyingType();
model.Extensions.Add("x-ms-enum", new
{
name = context.SystemType.Name,
modelAsString = false,
values = context.SystemType
.GetEnumValues()
.Cast<object>()
.Distinct()
.Select(value =>
{
//var t = context.SystemType;
//var convereted = Convert.ChangeType(value, enumUnderlyingType);
//return new { value = convereted, name = value.ToString() };
return new { value = value, name = value.ToString() };
})
.ToArray()
});
}
}
}

/// <summary>
/// Adds extra schema details for an enum in the swagger.json i.e. x-enumNames (used by NSwag to generate Enums for C# client)
/// https://github.com/RicoSuter/NSwag/issues/1234
/// </summary>
public class NSwagEnumExtensionSchemaFilter : ISchemaFilter
{
public void Apply(Schema model, SchemaFilterContext context)
{
if (model == null)
throw new ArgumentNullException("model");

if (context == null)
throw new ArgumentNullException("context");

if (context.SystemType.IsEnum)
{
var names = Enum.GetNames(context.SystemType);
model.Extensions.Add("x-enumNames", names);
}
}
}
}

Then in your startup.cs you configure them

        services.AddSwaggerGen(c =>
{
... the rest of your configuration

// REMOVE THIS to use Integers for Enums
// c.DescribeAllEnumsAsStrings();

// add enum generators based on whichever code generators you decide
c.SchemaFilter<NSwagEnumExtensionSchemaFilter>();
c.SchemaFilter<EnumFilter>();
});

This should generate your enums as this in the Swagger.json file

        sensorType: {
format: "int32",
enum: [
0,
1,
2,
3
],
type: "integer",
x-enumNames: [
"NotSpecified",
"Temperature",
"Fuel",
"Axle"
],
x-ms-enum: {
name: "SensorTypesEnum",
modelAsString: false,
values: [{
value: 0,
name: "NotSpecified"
},
{
value: 1,
name: "Temperature"
},
{
value: 2,
name: "Fuel"
},
{
value: 3,
name: "Axle"
}
]
}
},

There is one issue with this solution though, (which I haven't had time to look into)
Is that the Enum names are generated with my DTO names in NSwag - If you do find a solution to this do let me know :-)

Example, the following Enum was generated using NSwag:

Sample Image



Related Topics



Leave a reply



Submit