Создание "последней" версии документации Swagger с помощью Swashbuckle

Я работаю над общедоступным API, используя Swashbuckle.AspNetCore & ReDoc для документации с Microsoft.AspNetCore.Mvc.Versioning для управления версиями наших контроллеров с помощью атрибутов.

Мы хотим иметь масштабный документ, который показывает все последние версии наших конечных точек, чтобы людям, впервые обращающимся к API, было проще выбрать правильную версию.

Моя текущая попытка состояла в том, чтобы создать 'v0' и применить эту версию ко всем последним версиям контроллеров. Затем я использовал фильтр операций, чтобы заменить v0 на последнюю версию:

public class LatestVersionOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var version = (context.MethodInfo.GetCustomAttributes<ApiVersionAttribute>()
                .Union(context.MethodInfo.DeclaringType.GetCustomAttributes<ApiVersionAttribute>())
                .SelectMany(x => x.Versions)
                .OrderByDescending(x => x.MajorVersion))
                .FirstOrDefault(x => x.MajorVersion != 0);
        if (version != null && context.ApiDescription.RelativePath.Contains("v0"))
        {
            context.ApiDescription.RelativePath = context.ApiDescription.RelativePath
                .Replace("v0", $"v{version.MajorVersion}");
        }
    }
}

Это работает большую часть времени, но иногда кажется, что это не срабатывает, и вы получаете кучу URL-адресов с 'v0'. Фильтр работает, но, похоже, не отражается в итоговом документе swagger.

Есть ли лучший способ достичь того, к чему мы здесь стремимся? Я попытался написать что-то, используяDocInclusionPredicate но я не мог получить то, что хотел.

1 ответ

Решение

Еще немного покопавшись, я обнаружил эту старую проблему:https://github.com/domaindrivendev/Swashbuckle/issues/361

Раньше я пробовал использовать фильтр документов, но мне показалось, что идти по неверному пути. Увидев эту проблему, я сделал еще один шаг, и теперь для нас работает следующее:

public class LatestVersionDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        foreach (var path in swaggerDoc.Paths.ToList())
        {
            if (!path.Key.Contains("v0"))
            {
                continue;
            }

            var apiDescription = context.ApiDescriptions.FirstOrDefault(x => x.RelativePath == path.Key.TrimStart('/'));
            if (apiDescription != null && apiDescription.TryGetMethodInfo(out var methodInfo))
            {
                var latestVersion = methodInfo.GetCustomAttributes<ApiVersionAttribute>()
                    .Union(methodInfo.DeclaringType.GetCustomAttributes<ApiVersionAttribute>())
                    .SelectMany(x => x.Versions)
                    .OrderByDescending(x => x.MajorVersion)
                    .FirstOrDefault(x => x.MajorVersion != 0);

                if (latestVersion != null)
                {
                    swaggerDoc.Paths.Remove(path.Key);
                    var latestUrl = path.Key.Replace("/v0/", $"/v{latestVersion.MajorVersion}/");
                    swaggerDoc.Paths.Add(latestUrl, path.Value);
                }
            }
        }
    }
}
Другие вопросы по тегам