web-dev-qa-db-fra.com

Documentation Web Api de Swagger UI Les états énumérés sont-ils des chaînes?

Existe-t-il un moyen d'afficher toutes les énumérations comme valeur de chaîne dans swagger au lieu de leur valeur int?

Je veux être en mesure de soumettre des actions POST) et de mettre des énumérations en fonction de la valeur de leur chaîne sans avoir à les regarder à chaque fois.

J'ai essayé DescribeAllEnumsAsStrings mais le serveur reçoit alors des chaînes au lieu de la valeur enum, ce qui n'est pas ce que nous recherchons.

Quelqu'un at-il résolu ce problème?

Modifier:

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
}
60
user5326354

De les docs :

httpConfiguration
    .EnableSwagger(c => 
        {
            c.SingleApiVersion("v1", "A title for your API");

            c.DescribeAllEnumsAsStrings(); // this will do the trick
        });

De plus, si vous souhaitez que ce comportement concerne uniquement un type et une propriété particuliers, utilisez StringEnumConverter:

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

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

Donc, je pense avoir un problème similaire. Je recherche swagger pour générer des énumérations avec le mappage int -> string. L'API doit accepter l'int. Le swagger-ui importe moins, ce que je veux vraiment, c’est la génération de code avec une "vraie" énumération de l’autre côté (les applications Android utilisant la conversion dans ce cas).

Donc, d'après mes recherches, cela semble finalement être une limite de la spécification OpenAPI utilisée par Swagger. Il n'est pas possible de spécifier des noms et des numéros pour les enums.

Le meilleur problème que j'ai trouvé à suivre est https://github.com/OAI/OpenAPI-Specification/issues/681 qui ressemble à un "peut-être bientôt" mais Swagger devra être mis à jour , et dans mon cas Swashbuckle aussi.

Pour l'instant, ma solution consiste à implémenter un filtre de document qui recherche des énumérations et renseigne la description pertinente avec le contenu de cette énumération.

        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());
    }

}

Il en résulte quelque chose comme ce qui suit sur votre swagger-ui afin qu'au moins vous puissiez "voir ce que vous faites": enter image description here

34
Rory

Je voulais utiliser la réponse de rory_za dans une application .NET Core, mais je devais la modifier un peu pour que cela fonctionne. Voici l'implémentation que j'ai conçue pour .NET Core.

Je l'ai également changé pour ne pas supposer que le type sous-jacent est int et utiliser de nouvelles lignes entre les valeurs pour en faciliter la lecture.

/// <summary>
/// Add enum value descriptions to Swagger
/// </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)}";
    }
}

Ajoutez ensuite ceci à votre méthode ConfigureServices dans Startup.cs:

c.DocumentFilter<EnumDocumentFilter>();
17
Gabriel Luci

Je viens de faire ça et ça marche bien!

Startup.cs

services.AddSwaggerGen(c => {
  c.DescribeAllEnumsAsStrings();
});

Model.cs

public enum ColumnType {
  DATE = 0
}

swagger.json

type: {
  enum: ["DATE"],
  type: "string"
}

J'espère que cela vous aide comment cela m'a aidé!

4
Rodrigo Béco

DescribeAllEnumsAsStrings() n'a pas fonctionné pour moi car, comme OP l'a dit, le serveur reçoit des chaînes et attend des données. Pour permettre au serveur de s’attendre à des chaînes, j’estime que vous devez ajouter StringEnumConverter à SerializerSettings. De plus, vous pouvez laisser complètement DescribeAllEnumsAsStrings ().

tl; dr: Faites ceci dans Startup.cs/ConfigureServices ():

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

écrire du code dans Startup.cs

services.AddSwaggerGen(c => {
      c.DescribeAllEnumsAsStrings();
    });
3
Anjyr