Swagger UI Web Api documentation Present enums as strings?

161,841

Solution 1

Enable globally

From the docs:

httpConfiguration
    .EnableSwagger(c => 
        {
            c.SingleApiVersion("v1", "A title for your API");
            
            c.DescribeAllEnumsAsStrings(); // this will do the trick
        });

Enum/string conversion on particular property

Also, if you want this behavior only on a particular type and property, use the StringEnumConverter:

public class Letter 
{
    [Required]
    public string Content {get; set;}

    [Required]
    [EnumDataType(typeof(Priority))]
    [JsonConverter(typeof(StringEnumConverter))]
    public Priority Priority {get; set;}
}

If you're using Newtonsoft and Swashbuckle v5.0.0 or higher

You'll also need this package:

Swashbuckle.AspNetCore.Newtonsoft

And this in your startup:

services.AddSwaggerGenNewtonsoftSupport(); // explicit opt-in - needs to be placed after AddSwaggerGen()

There's docs here: https://github.com/domaindrivendev/Swashbuckle.AspNetCore#systemtextjson-stj-vs-newtonsoft

Solution 2

For ASP.NET Core 3 with the Microsoft JSON library (System.Text.Json)

In Startup.cs/ConfigureServices():

services
    .AddControllersWithViews(...) // or AddControllers() in a Web API
    .AddJsonOptions(options => 
        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));

For ASP.NET Core 3 with the Json.NET (Newtonsoft.Json) library

Install the Swashbuckle.AspNetCore.Newtonsoft package.

In Startup.cs/ConfigureServices():

services
    .AddControllersWithViews(...)
    .AddNewtonsoftJson(options => 
        options.SerializerSettings.Converters.Add(new StringEnumConverter()));
// order is vital, this *must* be called *after* AddNewtonsoftJson()
services.AddSwaggerGenNewtonsoftSupport();

For ASP.NET Core 2

In Startup.cs/ConfigureServices():

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

Pre-ASP.NET Core

httpConfiguration
    .EnableSwagger(c => 
        {
            c.DescribeAllEnumsAsStrings();
        });

Solution 3

So I think I have a similar problem. I'm looking for swagger to generate enums along with the int -> string mapping. The API must accept the int. The swagger-ui matters less, what I really want is code generation with a "real" enum on the other side (android apps using retrofit in this case).

So from my research this ultimately seems to be a limit of the OpenAPI specification which Swagger uses. It's not possible to specify names and numbers for enums.

The best issue I've found to follow is https://github.com/OAI/OpenAPI-Specification/issues/681 which looks like a "maybe soon" but then Swagger would have to be updated, and in my case Swashbuckle as well.

For now my workaround has been to implement a document filter that looks for enums and populates the relevant description with the contents of the enum.

        GlobalConfiguration.Configuration
            .EnableSwagger(c =>
                {
                    c.DocumentFilter<SwaggerAddEnumDescriptions>();

                    //disable this
                    //c.DescribeAllEnumsAsStrings()

SwaggerAddEnumDescriptions.cs:

using System;
using System.Web.Http.Description;
using Swashbuckle.Swagger;
using System.Collections.Generic;

public class SwaggerAddEnumDescriptions : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
    {
        // add enum descriptions to result models
        foreach (KeyValuePair<string, Schema> schemaDictionaryItem in swaggerDoc.definitions)
        {
            Schema schema = schemaDictionaryItem.Value;
            foreach (KeyValuePair<string, Schema> propertyDictionaryItem in schema.properties)
            {
                Schema property = propertyDictionaryItem.Value;
                IList<object> propertyEnums = property.@enum;
                if (propertyEnums != null && propertyEnums.Count > 0)
                {
                    property.description += DescribeEnum(propertyEnums);
                }
            }
        }

        // add enum descriptions to input parameters
        if (swaggerDoc.paths.Count > 0)
        {
            foreach (PathItem pathItem in swaggerDoc.paths.Values)
            {
                DescribeEnumParameters(pathItem.parameters);

                // head, patch, options, delete left out
                List<Operation> possibleParameterisedOperations = new List<Operation> { pathItem.get, pathItem.post, pathItem.put };
                possibleParameterisedOperations.FindAll(x => x != null).ForEach(x => DescribeEnumParameters(x.parameters));
            }
        }
    }

    private void DescribeEnumParameters(IList<Parameter> parameters)
    {
        if (parameters != null)
        {
            foreach (Parameter param in parameters)
            {
                IList<object> paramEnums = param.@enum;
                if (paramEnums != null && paramEnums.Count > 0)
                {
                    param.description += DescribeEnum(paramEnums);
                }
            }
        }
    }

    private string DescribeEnum(IList<object> enums)
    {
        List<string> enumDescriptions = new List<string>();
        foreach (object enumOption in enums)
        {
            enumDescriptions.Add(string.Format("{0} = {1}", (int)enumOption, Enum.GetName(enumOption.GetType(), enumOption)));
        }
        return string.Join(", ", enumDescriptions.ToArray());
    }

}

This results in something like the following on your swagger-ui so at least you can "see what you're doing": enter image description here

Solution 4

ASP.NET Core 3.1

To generate enums as strings using Newtonsoft JSON you must explicitly add Newtonsoft support by adding AddSwaggerGenNewtonsoftSupport() as follows:

services.AddMvc()
    ...
    .AddNewtonsoftJson(opts =>
    {
        opts.SerializerSettings.Converters.Add(new StringEnumConverter());
    });


services.AddSwaggerGen(...);
services.AddSwaggerGenNewtonsoftSupport(); //

This is available via a new package, Swashbuckle.AspNetCore.Newtonsoft. It looks like everything else works fine without this package apart from enum converter support.

Solution 5

.NET CORE 3.1 and SWAGGER 5

if you need a simple solution to selectively make enums passed as strings:

using System.Text.Json.Serialization;


[JsonConverter(typeof(JsonStringEnumConverter))]
public enum MyEnum
{
    A, B
}

Note, we use System.Text.Json.Serialization namespace, not the Newtonsoft.Json!

Share:
161,841

Related videos on Youtube

Admin
Author by

Admin

Updated on April 29, 2022

Comments

  • Admin
    Admin almost 2 years

    Is there a way to display all enums as their string value in swagger instead of their int value?

    I want to be able to submit POST actions and put enums according to their string value without having to look at the enum every time.

    I tried DescribeAllEnumsAsStrings but the server then receives strings instead of the enum value which is not what we're looking for.

    Has anyone solved this?

    Edit:

    public class Letter 
    {
        [Required]
        public string Content {get; set;}
    
        [Required]
        [EnumDataType(typeof(Priority))]
        public Priority Priority {get; set;}
    }
    
    
    public class LettersController : ApiController
    {
        [HttpPost]
        public IHttpActionResult SendLetter(Letter letter)
        {
            // Validation not passing when using DescribeEnumsAsStrings
            if (!ModelState.IsValid)
                return BadRequest("Not valid")
    
            ..
        }
    
        // In the documentation for this request I want to see the string values of the enum before submitting: Low, Medium, High. Instead of 0, 1, 2
        [HttpGet]
        public IHttpActionResult GetByPriority (Priority priority)
        {
    
        }
    }
    
    
    public enum Priority
    {
        Low, 
        Medium,
        High
    }
    
    • Hux
      Hux almost 8 years
      Do you want the schema to describe the value as a string but then post an integer to the server? JSON.net will handle both values fine, so is the integer only version a definite requirement? I don't think Swagger supports a enum type with both the string and integer value.
    • Federico Dipuma
      Federico Dipuma almost 8 years
      Your expected behavior is unclear, can you better explain what you want Swagger UI to display and what you want to POST/PUT to your Web API with examples?
    • Admin
      Admin almost 8 years
      Moreover, if I have GET methods that take enum in the url, I want the scheme to describe it as strings in the drop down list of suggested values
    • Hux
      Hux almost 8 years
      Why does integer validation fail? The type should be an enum in the model and the json media formatter would correctly handle either a string or int. If you update the question with an example it would help us understand why the validation is failing.
    • Admin
      Admin almost 8 years
      I added code example, hope it will be clear
    • Triynko
      Triynko about 6 years
      If it's a flags enum, the it has to be numeric, unless you have enum values defined for every possible combination of flags. It's nuts that swagger doesn't display BOTH the name and value for each enum, and instead displays number alone (useless) or names alone (again, useless for flags which must be specified as numbers).
  • Lineker
    Lineker over 6 years
    this doesn't work for me.[EnumDataType(typeof(Priority))] [JsonConverter(typeof(StringEnumConverter))]
  • Lineker
    Lineker over 6 years
    @NH. yes, i used newtonsoft.json
  • NH.
    NH. over 6 years
    @Lineker, post your error as a new question, following this guide: stackoverflow.com/help/mcve
  • NSGaga-mostly-inactive
    NSGaga-mostly-inactive over 6 years
    +1 I was looking to add descriptions to enums (just to 'describe enum'), never thought of this. I already have misc filters in place, but was looking for something more 'organic', but there's no support. Well then, filters all the way :)
  • aruno
    aruno about 6 years
    Thx! I think I might just leave your comment in the source too #thiswilldothetrick
  • aruno
    aruno about 6 years
    Hmm why is EnumDataType required? Is there a way to make it smart enough to auto detect
  • Xavero
    Xavero about 6 years
    if you use the line with "#thiswilldothetrick", you dont need the StringEnumConverterAttribute. The Attibutes are only required when you want this feature in a specific Property. Also, I dont remember what the EnumDataTypeAttribute does, but perphaps you dont need it.
  • Gabriel Luci
    Gabriel Luci almost 6 years
    Thanks! I used this in my project, but modified it to work with .NET Core. I added my implementation as an answer.
  • Softlion
    Softlion over 5 years
    Possible to remove the Enum: Array [ 6 ] which appears below ?
  • spottedmahn
    spottedmahn over 5 years
    ASP.NET Core documentation: Customize Schema for Enum Types
  • Jerico Sandhorn
    Jerico Sandhorn over 5 years
    worked instantly for me. How do I make them lower case now?
  • Xavero
    Xavero over 5 years
    I think the Lowercase its achieved with the Json converter/Newtonsoft, but i am not sure.
  • Xavero
    Xavero over 5 years
    Oh, nevermind, sppotedmahn's link shows how to do it: c.DescribeStringEnumsInCamelCase();
  • bugged87
    bugged87 over 5 years
    DescribeAllEnumsAsStrings worked for object properties and even query parameters on controller actions. However, using EnumDataTypeAttribute and JsonConverter(typeof(StringEnumConverter)) did not work for me.
  • Rabban
    Rabban over 5 years
    Great solution, but the extensions in DescribeEnumParameters were empty in my project. I had to cast the param to NonBodyParameter and check the enum there: if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) { param.Description += DescribeEnum(nbParam.Enum); }
  • Carlos Beppler
    Carlos Beppler about 5 years
    On my project Extensions is empty too, used the @Rabban solution.
  • Gabriel Luci
    Gabriel Luci almost 5 years
    @Rabban I updated my code to include that. Can you just verify I put it in the right place? I didn't have this issue. Maybe a newer version changed things.
  • Rabban
    Rabban almost 5 years
    @GabrielLuci Confirmed and approved ;)
  • Bashir Momen
    Bashir Momen over 4 years
    It is using Newtonsoft instead of new asp.net core JSON serialization.
  • Bernard Vander Beken
    Bernard Vander Beken over 4 years
    Hey @Bashir, is there a swachbuckle issue to keep track of the lack of that support?
  • Bashir Momen
    Bashir Momen over 4 years
    Hi @bernard-vander-beken, I did not report that but I assume there is. It is good if we can find it and add it to this post for a later updates.
  • Bashir Momen
    Bashir Momen over 4 years
    This option is deprecated in the Swashbuckle. It is recommended to use the ASP.NET Core option and then Swashbuckle can reflect that.
  • Node.JS
    Node.JS over 4 years
    DescribeAllEnumsAsStrings is deprecated
  • jeremyh
    jeremyh over 4 years
  • Guillaume
    Guillaume over 4 years
    Problem of using options.SerializerSettings.Converters.Add(new StringEnumConverter())) is that your changing the json for all your methods, not only for Sawshbuckle.
  • Rocklan
    Rocklan over 4 years
    Solution works great, thanks so much. Any reason why DescribeEnumParameters is static?
  • Gabriel Luci
    Gabriel Luci over 4 years
    @Rocklan Because it can be :) And static methods are slightly more efficient than ones that aren't.
  • A. Tretiakov
    A. Tretiakov about 4 years
    This solution omits important step of registering StringEnumConverter as a converter in AddNewtonsoftJson section of AddMvc. See example in @Roman Starkov answer below.
  • A. Tretiakov
    A. Tretiakov about 4 years
    It helps to setup this convention globally, but if you need to apply this only to certain types of enums, you will need to carefully read this issue. TL; DR: It's not possible to apply new StringEnumConverter() to property only, but you can apply it to the whole enum type.
  • Roman Starkov
    Roman Starkov about 4 years
    I suppose if we're talking of gotchas, it's also not possible to use a completely custom converter. Swagger doesn't run the enum values through the custom converter; it simply recognizes StringEnumConverter as a special case.
  • user2864740
    user2864740 about 4 years
    GetMembers() would be better as GetMembers(BindingFlags.Static | BindingFlags.Public) to limit to only the actual declared enum properties such as "Blue". I also adapted the "else" case to return the Member.Name if there is no [EnumMember] attribute.
  • Matyas
    Matyas almost 4 years
    Down side of this is, that when executing a request, instead of passing only int representation (like 2 for example) of an enum value the API will get the full description as a value (like LogicError = 3), which will fail as a bad request since it is not valid value for the enum.
  • Matyas
    Matyas almost 4 years
    This only works when the parameter type is exactly enum... not nullable enum, collection of enums etc. Check my answer for those cases.
  • Dan Friedman
    Dan Friedman almost 4 years
    Does anyone have a solution for Azure Functions v2 and/or v3?
  • lsuarez
    lsuarez almost 4 years
    You should also ensure that you update the model.Format to "string" as it will generally be "int32".
  • MovGP0
    MovGP0 almost 4 years
    This one works showing the proper values, and also works when converting the values back to the enum. Note that you need to add the NuGet package System.Text.Json.
  • Nilay Mehta
    Nilay Mehta almost 4 years
    That's what I was looking for! As I have to use string for just single enum, and DescribeAllEnumsAsStrings will convert all enums to the string.
  • Ian Kemp
    Ian Kemp over 3 years
    @DanFriedman Considering Swashbuckle doesn't work with Azure Functions at all, you're out of luck.
  • wolfyuk
    wolfyuk over 3 years
    @IanKemp There is third party support with the AzureExtensions.Swashbuckle package but like @DanFriedman I cannot get the enum-to-string working as expected
  • Kirsten
    Kirsten over 3 years
    When I run this code I find that enumOption is of type OpenApiString in DescribeEnum
  • Mahesh
    Mahesh over 3 years
    Thanks for this simple solution. I'm using .NET Core 3.1 and Swagger 5.5. didn't need to use DescribeAllEnumsAsStrings . Just set [JsonConverter(typeof(JsonStringEnumConverter))] on enum. EX: System.Text.Json.Serialization; [JsonConverter(typeof(JsonStringEnumConverter))] public enum Category { Autos, Electronics, Furniture, House, Pets, Miscellaneous }
  • Andy Vaal
    Andy Vaal over 3 years
    If you're configuring for ASP.NET Core 3 with Newtonsoft, the AddSwaggerGenNewtonsoftSupport() extension method is available from NuGet packageSwashbuckle.AspNetCore.Newtonsoft. Read more here: github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/maste‌​r/…
  • Yaroslav Bres
    Yaroslav Bres over 3 years
    Your solution is working, only if I change GetEnumTypeByName FirstOfDefaultCondition to this .FirstOrDefault(x => x.FullName == enumTypeName || x.Name == enumTypeName);
  • fingers10
    fingers10 over 3 years
    This worked for me. If you are using Newtonsoft Json in your asp.net core project. The you need to explicitly this. Thanks @user30844147
  • developer learn999
    developer learn999 over 3 years
    this works only on Core3.0, filter not exist in Core2
  • developer learn999
    developer learn999 over 3 years
    in core2.0 it displays the keys, but not the values as expected. also data member description not works see stackoverflow.com/questions/64764537/…
  • developer learn999
    developer learn999 over 3 years
    what value should i put above each value? currently i get error : - $exception {"Type provided must be an Enum.\r\nParameter name: enumType"} System.ArgumentException
  • computercarguy
    computercarguy over 3 years
    c.DescribeAllEnumsAsStrings(); is deprecated in Swagger 5.6.0.
  • Cubicle.Jockey
    Cubicle.Jockey over 3 years
    A very important step.
  • ehsan rezaee
    ehsan rezaee about 3 years
    ApiResult is a response class . validation of enum in imput parameter is another discuese in .core you can use IValidatableObject and implementation : public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) on object
  • sasi reka
    sasi reka about 3 years
    It works in .Net 5. DescribeAllEnumsAsStrings (deprecated) and AddSwaggerGenNewtonsoftSupport is not working in .Net 5.
  • Askolein
    Askolein about 3 years
    In .NET core 5, the .Converters.Add(..) approach does not work for me, while the [JsonConverter(typeof(StringEnumConverter))] without having any other settings. Any idea why?
  • Azimuth
    Azimuth almost 3 years
    AddNewtonsoftJson accepts IMvcBuilder. It won't work with IServiceCollection. Please fix your code for For ASP.NET Core 3 with the Json.NET (Newtonsoft.Json) library.
  • manymanymore
    manymanymore almost 3 years
    Where can I get the httpConfiguration object?
  • Maulik Modi
    Maulik Modi almost 3 years
    What is the recommended solution in .net 5?
  • Maulik Modi
    Maulik Modi almost 3 years
    Is there any global option instead of decorating POCOs with Json converter attributes? How does it appear in swagger doc? Does it generate Enum on the client side code generation as well?
  • TK-421
    TK-421 almost 3 years
    I had to update the model.Type to "string" for the same reason Isuarez mentioned.
  • HenryMigo
    HenryMigo almost 3 years
    Only thing that worked for me for what I wanted.
  • Nicholas Petersen
    Nicholas Petersen over 2 years
    Bravo. While I am forced to continue using Newtonsoft.Json, I didn't necessarily need that to be recognized in the API documentation generation, I just needed enums to be represented as strings. Barring a more complicated scenario (like custom newtonsoft enum names), surprisingly this just worked.
  • sergeyxzc
    sergeyxzc over 2 years
    Thanks! This is what helped me in my net5 project
  • vahid
    vahid over 2 years
    @MaulikModi In Swagger doc, it changes the type to string and provides a list of available values.
  • Amir Chatrbahr
    Amir Chatrbahr over 2 years
    few tweaks to make it work: 1- model.Format = null; 2- model.Type = "string";
  • Ulterior
    Ulterior over 2 years
    This was actually what worked with NSwagStudio export
  • Rich Hopkins
    Rich Hopkins about 2 years
    I spent three days looking for this. Tried stuff that involved other libraries, but didn't give me what I needed. Here you go showing me how to do it in 4 lines of code. Thanks!
  • John Demetriou
    John Demetriou about 2 years
    This doesn't exist. Any alternatives?
  • OhWelp
    OhWelp about 2 years
    This will render your swagger requests unusable as it will overwrite your int representation of value. Use with caution.
  • ping
    ping over 1 year
    Thank you, this works fine and is exactly what i was looking for. But it rises a new issue. The example JSON value of the request in the Swagger UI, shows the required enum as defined in the EnumSchemaFilter which results in: { ...."language": "en(1)",...}. The "Try it out" and then 'execute' button won't work whit this adaption. Any improvement advises for this issue?
  • Kiquenet
    Kiquenet over 1 year
    and for NET 6 minimal API ?