Создание "последней" версии документации 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);
}
}
}
}
}