Gabriel Ribeiro
Gabriel Ribeiro

Reputation: 51

C# - Ordering required params from abstract class in Swagger API documentation

I've searched a lot before asking this question, but all I found were related to other themes, like ordering paths in swagger doc.

I can show what my problem is by this simple example:

abstract class Animal
{
   [Required]
   public string Name { get; set; }
}

class Dog : Animal 
{
   [Required]
   public bool CanBark { get; set; }
   
   public Color DogColor { get; set; }
}

But in my generated Swagger API documentation, the params appear in this order:

  1. CanBark (required)
  2. DogColor
  3. Name (required)

Basically, I want to change the order they appear in the generated documentation. SO, in order to do that, I created a class in SwashBuckleConfig.cs

    internal class SortBodyParams : IDocumentFilter
    {
        public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
        {
            var properties = schemaRegistry.Definitions.Values;
            foreach (var prop in properties) // Maybe something like this
            {
                // Order params by Required type and by name

                // This code doesn't change anything, 
                // although I thought it would help to order params by name
                prop.properties
                    .OrderBy(x => x.Key)
                    .ToList()
                    .ToDictionary(x => x.Key, y => y.Value);
            }
        }
    }

And called the class from the Register method:

        public static void Register(HttpConfiguration config)
        {
            config
                .EnableSwagger(sdc =>
                {
                    ...

                    sdc.DocumentFilter<SortBodyParams>();

                    ...
                }
         }

Does anybody can help me to order the required params first and also order them by name?

Upvotes: 1

Views: 708

Answers (1)

Gabriel Ribeiro
Gabriel Ribeiro

Reputation: 51

After a long time trying to solve this problem, I finally came up with a solution:

internal class SortBodyParams : IDocumentFilter
    {
        private Schema _schema = new Schema();

        public void Apply(
            SwaggerDocument swaggerDoc, 
            SchemaRegistry schemaRegistry, 
            IApiExplorer apiExplorer)
        {
            foreach (var schema in schemaRegistry.Definitions.Values)
            {
                _schema = schema;

                var allFields = GetAllFieldsInSchema();
                var reqFields = GetAllRequiredFieldsInSchema();

                _schema.properties.Clear();

                AddAllRequiredFieldsInSchema(allFields, reqFields);
                AddAllOptionalFieldsInSchema(allFields, reqFields);
            }
        }

        public Dictionary<string, Schema> GetAllFieldsInSchema()
        {
            return _schema.properties
                    .OrderBy(x => x.Key)
                    .ToList()
                    .ToDictionary(x => x.Key, y => y.Value);
        }

        public IList<string> GetAllRequiredFieldsInSchema()
        {
            var requiredFields = _schema.required;
            if (ThereAreRequiredFields())
            {
                return requiredFields
                        .OrderBy(x => x)
                        .ToList();
            }
            return requiredFields;
        }

        public void AddAllRequiredFieldsInSchema(
            Dictionary<string, Schema> allFields,
            IList<string> reqFields)
        {
            if (ThereAreRequiredFields())
            {
                int index = 0;
                int notAllowedIndex = reqFields.Count;
                foreach (var field in allFields)
                {
                    if (field.Key == reqFields[index])
                    {
                        _schema.properties.Add(field.Key, field.Value);
                        index++;

                        if (index == notAllowedIndex) break;
                    }
                }
            }
        }

        public void AddAllOptionalFieldsInSchema(
            Dictionary<string, Schema> allFields, 
            IList<string> reqFields)
        {
            foreach (var field in allFields)
            {
                if (ThereAreRequiredFields())
                {
                    if (!reqFields.Contains(field.Key))
                    {
                        _schema.properties.Add(field.Key, field.Value);
                    }
                }
                else
                {
                    _schema.properties.Add(field.Key, field.Value);
                }
            }
        }

        public bool ThereAreRequiredFields()
        {
            if (_schema.required != null)
            {
                return true;
            }

            return false;
        }
    }

To solve my problem, I only had to remove all fields and add them the order I wanted.

Upvotes: 1

Related Questions