Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I change order the operations are listed in a group in Swashbuckle?

I'm using Swashbuckle to generate Swagger UI. It has options for choosing a grouping key (controller by default) and the ordering of the groups, but I would like to choose an order for the operations in a group so that GET appears always before DELETE for example.

I've found how to implement document filters and I can get and order ApiDescriptions by HttpMethod, but changing the order in ApiDescriptions doesn't reflect in the generated Swagger UI and I can't find how to persist the order in swaggerDoc.

SwaggerDocument has a paths property, but the PathItem in it has each HTTP method as a property, so I can't figure how to choose an order of presentation for them. Eventough, when the Swagger UI for my API is generated, different controllers get different method order in the page.

Should I manually reorder the methods implementation in my controller instead?

like image 490
lpacheco Avatar asked Sep 21 '17 08:09

lpacheco


2 Answers

In order to order the Operations of controller in swagger OpenApi paths json spec you could create a custom Attribute OrderAttribute and then a IDocumentFilter which will reorder the OpenApiPaths.

public class OperationsOrderingFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument openApiDoc, DocumentFilterContext context)
    {
        Dictionary<KeyValuePair<string, OpenApiPathItem>,int> paths = new Dictionary<KeyValuePair<string, OpenApiPathItem>, int>();
        foreach(var path in openApiDoc.Paths)
        {
            OperationOrderAttribute orderAttribute = context.ApiDescriptions.FirstOrDefault(x=>x.RelativePath.Replace("/", string.Empty)
                .Equals( path.Key.Replace("/", string.Empty), StringComparison.InvariantCultureIgnoreCase))?
                .ActionDescriptor?.EndpointMetadata?.FirstOrDefault(x=>x is OperationOrderAttribute) as OperationOrderAttribute;

            if (orderAttribute == null)
                throw new ArgumentNullException("there is no order for operation " + path.Key);

            int order = orderAttribute.Order;
            paths.Add(path, order);
        }

        var orderedPaths = paths.OrderBy(x => x.Value).ToList();
        openApiDoc.Paths.Clear();
        orderedPaths.ForEach(x => openApiDoc.Paths.Add(x.Key.Key, x.Key.Value));
    }

}

then the attribute would be

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class OperationOrderAttribute : Attribute
{
    public int Order { get; }

    public OperationOrderAttribute(int order)
    {
        this.Order = order;
    }
}

the registration of the filter in swagger would be

services.AddSwaggerGen(options =>
{
   options.DocumentFilter<OperationsOrderingFilter>();
}

and an example of a controller method with the attribute would be:

[HttpGet]
[OperationOrder(2)]
[Route("api/get")]
public async Task<ActionResult> Get(string model)
{
   ...
}
like image 143
dkokkinos Avatar answered Oct 25 '22 08:10

dkokkinos


Had the same issue, and finally managed to fix it with the official doc. provided on this URL https://github.com/domaindrivendev/Swashbuckle.AspNetCore#change-operation-sort-order-eg-for-ui-sorting

services.AddSwaggerGen(c =>
{
...
c.OrderActionsBy((apiDesc) => $"{apiDesc.ActionDescriptor.RouteValues["controller"]}_{apiDesc.HttpMethod}");
};

Is an easier and clearer path to solve it :)

like image 28
Kaitiff Avatar answered Oct 25 '22 06:10

Kaitiff