Если вы создавали Web API на .NET в последние несколько лет, то наверняка сталкивались с зелёным интерфейсом Swagger UI. Этот инструмент стал практически стандартом для документирования и тестирования API. Однако, с выходом .NET 9 многие разработчики были удивлены: знакомый Swagger больше не добавляется автоматически в шаблоны проектов. Что произошло, почему Microsoft решила избавиться от Swagger и чем теперь документировать свои API?
Для начала стоит понять, что Swagger — это целая спецификация (ныне известная как OpenAPI), которая позволяет описывать REST API стандартизированным способом. Swashbuckle — популярная библиотека, которая добавляет поддержку Swagger/OpenAPI в проекты ASP.NET Core. Именно она до недавнего времени автоматически подключалась в шаблонах web API. Проблемы начались с поддержкой и обновлением Swashbuckle. За годы использования выявились серьёзные недостатки: основные контрибьюторы отошли от проекта, накопилось множество нерешённых багов и особенно остро встала проблема совместимости с новыми версиями .NET. К моменту выхода .NET 8 Swagger столкнулся с полной несовместимостью и отсутствием должной поддержки. Все это приводило к регулярным проблемам при обновлении проектов и к ограничениям возможностей WebAPI.
"Конфликты версий между Swashbuckle и новыми версиями .NET — головная боль многих команд," — часто слышу я от коллег на митапах. Разработчики вынуждены были делать выбор: либо откладывать обновление фреймворка, либо тратить время на поиск обходных путей для совместимости Swagger. Еще один важный нюанс — ограниченная поддержка минимальных API. С появлением минимальных API в .NET 6 начались проблемы с их документированием через Swagger. Некоторые важные метаданные просто игнорировались или отображались неверно.
Для микросервисной архитектуры стандартный Swagger оказался не лучшим выбором. Во-первых, каждый микросервис имел собственную Swagger-документацию, не связанную с другими. Агрегировать и представить все API как единую систему было непросто. Во-вторых, при большом количестве микросервисов обновление Swagger в каждом из них при выходе новой версии .NET превращалось в пытку. Сложность настройки безопасности — ещё один аспект, который часто вызывал недовольство разработчиков. Дополнительные атрибуты авторизации, описание различных схем безопасности, тестирование защищенных эндпоинтов требовали дополнительной конфигурации и кода.
Всё это подтолкнуло Microsoft к радикальному решению — исключить Swashbuckle из стандартных шаблонов .NET 9 и разработать нативное решение на основе пакета Microsoft.AspNetCore.OpenApi. Теперь у разработчиков появились новые возможности и альтернативы, которые мы рассмотрим в этой статье.
Критические недостатки Swagger с точки зрения безопасности API
Помимо проблем с поддержкой, Swagger имеет серьёзные недостатки в области безопасности, которые заставляют разработчиков искать альтернативы. Один из самых опасных аспектов — это публичное раскрытие полной структуры API. По умолчанию Swagger UI показывает все эндпоинты, параметры и схемы данных, что делает его отличной мишенью для потенциальных атакующих. Представь, что ты случайно забыл отключить Swagger в продакшн-среде — злоумышленники получат исчерпывающую карту вашего API.
С точки зрения защиты информацыи, стандартная конфигурация Swagger не предусматривает тонкую настройку видимости документации для разных пользователей. Это создаёт ситуацию "всё или ничего" — либо полный доступ к документации, либо полное её отключение. В результате внутренние API часто остаются без документации из соображений безопасности. Отдельного внимания заслуживает вопрос утечки чувствительных данных. Swagger автоматически генерирует примеры запросов и ответов, иногда включая в них информацию, которую не следовало бы разглашать: внутренние идентификаторы, структуру базы данных, имена серверов и т.д.
"Как-то раз на проекте мы обнаружили, что через примеры ответов в Swagger просачивается информация о схеме шардирования нашей базы данных — потенциальное золото для хакера", — вспоминает один из архитекторов нашей команды.
Ещё одна головная боль — тестирование защищенных эндпоинтов. Хотя Swagger UI предлагает механизм авторизации, его настройка зачастую неинтуитивна и ограничена. Для сложных схем аутентификации приходится писать дополнительный код, создавать фильтры безопасности, и даже тогда не всегда получается достичь желаемого результата.
php swagger api, вывод response XmlContent - <notagname> Когда я пытаюсь структурировать XmlContent для response в Swagger, то в итоге при выводе Xml... Open API, REST API и Swagger Open API - является спецификацией для описания REST API.
1. Что такое спецификация Open API?... В списке Target Framework не выбирается .NET Framework 4 только .NET Framework 4 Client Profile Свойства проекта (Project -> Properties) -> вкладка Compile -> Advenced complie options -> в списке... Как работать с интернет в VB.NET и С#.Net ??? Как работать с интернет в VB.NET и С#.Нет ???
а то в вб подключил компонент Мсинет.окс, и работай,...
NSwag: расширенные возможности для .NET
NSwag — это не просто достойная альтернатива Swagger, а полноценный инструмент нового поколения для документирования API. Использование NSwag в .NET-проектах открывает разработчикам гораздо более широкие возможности, чем предлагал классический Swagger. Одно из главных преимуществ NSwag — полная интеграция с ASP.NET Core и поддержка минимальных API. В отличии от Swashbuckle, все метаданные минимальных API корректно распознаются и отображаются. Это особенно важно, когда твой проект активно использует эту парадигму для создания легковесных эндпоинтов.
Встроенная генерация клиентского кода — еще один козырь NSwag. Возможность автоматически создавать клиентские библиотеки для TypeScript, C#, jQuery и других платформ существенно ускоряет разработку. Больше не нужно писать вручную классы для взаимодействия с API или возиться с дополнительными инструментами — всё это умеет NSwag из коробки.
C# | 1
2
3
4
5
6
7
8
9
10
| // Установка NSwag из NuGet
dotnet add package NSwag.AspNetCore
// Базовая настройка в Program.cs
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApiDocument(); // Это заменяет AddSwaggerGen()
// Конфигурация в цепочке middleware
app.UseOpenApi(); // Генерирует JSON-спецификацию
app.UseSwaggerUi3(); // Добавляет Swagger UI |
|
Производительность NSwag также заслуживает похвалы. Оптимизированый процесс генерации спецификации работает быстрее, особено в крупных проектах со сложными моделями. Я наблюдал случаи, когда замена Swashbuckle на NSwag сокращала время запуска приложения на несколько секунд — что немаловажно в циклах разработки.
Гибкость настройки документации выходит на новый уровень. NSwag позволяет указать информацию о версиях, теги, группировку эндпоинтов, расширенные описания и даже кастомные шаблоны для UI. Пример расширенной настройки:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| services.AddOpenApiDocument(options => {
options.DocumentName = "v1";
options.Title = "MyAwesomeAPI";
options.Version = "1.0";
options.Description = "API для управления чем-то очень важным";
// Группировка по контроллерам
options.DocumentProcessors.Add(new TagByControllerNameProcessor());
// Кастомные схемы безопасности
options.AddSecurity("JWT", new OpenApiSecurityScheme {
Type = OpenApiSecuritySchemeType.ApiKey,
Name = "Authorization",
In = OpenApiSecurityApiKeyLocation.Header,
Description = "Введите JWT токен: Bearer {token}"
});
}); |
|
В отличие от Swagger, NSwag предлагает несколько вариантов UI для документации – от классического Swagger UI до альтернативных интерфейсов вроде ReDoc. Это дает возможность выбрать более подходящий вариант под конкретные требования проекта и предпочтения команды.
Еще одной мощной стороной NSwag является возможность контролировать генерацию схем данных. Часто в проектах встречаются рекурсивные модели или сложные иерархии классов, с которыми Swagger не справляется элегантно. NSwag предлагает более тонкие механизмы контроля:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
| options.SchemaSettings.SchemaProcessors.Add(
new NSwag.Generation.Processors.SchemaProcessor(
(schema, type) =>
{
if (type == typeof(MyComplexType))
{
// Модифицируем схему для сложного типа
schema.Properties["sensitiveInfo"] = null;
}
}
)
); |
|
В рамках моей работы над высоконагруженным B2B API, мы столкнулись с проблемой избыточности документации, генерируемой стандартным Swagger. У нас было более 300 эндпоинтов и сотни сложных моделей. NSwag помог организовать их в логические группы, скрывая внутренние детали.
Механизм фильтрации операций — еще одна недооценённая фишка NSwag. Когда нужно скрывать определённые эндпоинты или модифицировать их описание в зависимости от окружения, такая возможность становится неоценимой:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| options.OperationProcessors.Add(
new OperationSecurityProcessor(
(operation, context) =>
{
// Например, скрываем админский функционал в публичной документации
if (operation.Tags.Contains("AdminOnly") && !context.IsAdminView)
{
return false; // Операция будет скрыта
}
return true;
}
)
); |
|
Когда речь заходит об API, которое постоянно эволюционирует, NSwag предлагает элегантное решение для версионирования. Вы можете генерировать отдельные спецификации для разных версий и переключаться между ними в UI:
C# | 1
2
3
4
5
6
7
8
9
10
11
| services.AddOpenApiDocument(config => {
config.DocumentName = "v1";
config.ApiGroupNames = new[] { "v1" };
// Настройки для v1
});
services.AddOpenApiDocument(config => {
config.DocumentName = "v2";
config.ApiGroupNames = new[] { "v2" };
// Настройки для v2
}); |
|
Интеграция с валидацией данных тоже реализована на высоком уровне. NSwag автоматически распознаёт атрибуты валидации из System.ComponentModel.DataAnnotations, превращая их в ограничения в OpenAPI-спецификации. Такое сквозное применение валидационных правил — боль всех API-разработчиков — с NSwag стало гораздо проще.
Генерация клиентского кода с помощью NSwag для различных платформ
Одна из самых мощных особенностей NSwag — это генерация клиентского кода на основе OpenAPI-спецификации. Если ты когда-нибудь писал клиентский код для взаимодействия с API вручную, ты знаешь, насколько это утомительно и подвержено ошибкам. NSwag решает эту проблему элегантно, автоматизируя весь процесс. Начнём с того, что NSwag поддерживает генерацию клиентов для впечатляющего количества платформ и языков: C#, TypeScript, JavaScript, Angular, Vue, React и даже старичок jQuery. Причём качество генерируемого кода гораздо выше, чем у конкурентов.
Для генерации кода есть два основных подхода: интеграция в процесс сборки и использование NSwag Studio — графического инструмента для управления генерацией. Вот пример настройки генерации TypeScript-клиента прямо в процессе сборки:
C# | 1
2
3
4
5
6
7
8
| services.AddOpenApiDocument(config => {
config.GenerateControllers = true; // Генерировать контроллеры
config.GenerateTypescript = true; // Включить генерацию TypeScript
config.TypeScriptGeneratorSettings.TypeScriptVersion = 4.3;
config.TypeScriptGeneratorSettings.Template = TypeScriptTemplate.Fetch;
config.TypeScriptGeneratorSettings.DateTimeType = TypeScriptDateTimeType.String;
config.TypeScriptGeneratorSettings.OutputPath = "ClientApp/src/api-client.ts";
}); |
|
Сгенерированый клиентский код не просто охватывает вызовы API, но и включает полную систему типов, соответствующую моделям вашего API. Это означает, что клиенты получают полный IntelliSense и типобезопасность при работе с вашим API. Например, для C# можно настроить генерацию так:
C# | 1
2
3
4
5
| options.CSharpGeneratorSettings.Namespace = "MyCompany.ApiClient";
options.CSharpGeneratorSettings.GenerateClientInterfaces = true;
options.CSharpGeneratorSettings.GenerateDtoTypes = true;
options.CSharpGeneratorSettings.ClientClassAccessModifier = "public";
options.CSharpGeneratorSettings.UseHttpClientCreationMethod = true; |
|
Интересная фишка для TypeScript — возможность выбрать тип HTTP-клиента. NSwag поддерживает различные способы HTTP-взаимодействия: Fetch API, Axios, Angular HttpClient и даже jQuery Ajax. Выбирай тот, который лучше соответствует вашему фронтенд-стеку:
C# | 1
2
3
4
5
6
7
| // Для Angular проектов
config.TypeScriptGeneratorSettings.Template = TypeScriptTemplate.Angular;
config.TypeScriptGeneratorSettings.InjectionTokenType = InjectionTokenType.InjectionToken;
config.TypeScriptGeneratorSettings.AngularVersion = 13;
// Для обычного TypeScript с Axios
config.TypeScriptGeneratorSettings.Template = TypeScriptTemplate.Axios; |
|
На проекте финтех-маркетплейса мы обнаружили удивительный побочный эффект автоматической генерации клиентов — заставить различные команды придерживаться согласованных моделей данных стало гораздо проще. Ведь теперь фронтенд-команда автоматически получает уведомления о любых изменениях в API через изменения в сгенерированном коде.
Для тех, кто создаёт мобильные приложения, NSwag может генерировать не только C# клиенты для Xamarin, но и Dart/Flutter код. Хотя последнее требует небольших дополнительных настроек:
C# | 1
2
3
| // Использование доп. генератора для Dart
services.AddOpenApiDocument()
.AddCustomProcessor(new DartClientGeneratorProcessor("MyApi", "./lib/api_client.dart")); |
|
Для микросервисной архитектуры генерация клиентов особенно ценна, поскольку позволяет сервисам легко интегрироваться друг с другом без дублирования контрактов и моделей. NSwag поддерживает генерацию кода с инжектированием HTTP-клиента, что упрощает внедрение зависимостей и тестирование.
Расширенные возможности настройки и темизации NSwag UI
NSwag выгодно отличается от классического Swagger гибкостью в настройке интерфейса. Если стандартный UI с зелёной шапкой приелся или не соответствует фирменному стилю, NSwag предлагает богатый арсенал возможностей для кастомизации.
Начнем с базовых настроек. В NSwag можно легко изменить цвета, логотип и общий стиль без особых трудов:
C# | 1
2
3
4
5
6
7
8
| app.UseSwaggerUi3(options =>
{
options.CustomStylesheets.Add("./custom-styles.css");
options.CustomJavaScripts.Add("./branding.js");
options.DocExpansion = "list"; // Варианты: none, list, full
options.DefaultModelsExpandDepth = 1;
options.TagsSorter = "alpha"; // Сортировка тегов/групп
}); |
|
Для более радикальных изменений можно полностью заменить шаблон интерфейса. NSwag позволяет указать кастомный HTML-шаблон, что даёт безграничные возможности для переработки UI:
C# | 1
2
3
4
| options.CustomDocumentTitle = "API Документация ФинтехСтарт";
options.CustomHeadContent =
"<meta name=\"description\" content=\"Интерактивная документация API\">";
options.CustomHtmlTemplate = File.ReadAllText("./SwaggerTemplate.html"); |
|
Один из моих любимых трюков — добавление интерактивных элементов. Например, можно встроить форму обратной связи или ссылки на документацию прямо в UI:
JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
| // branding.js
$(function() {
// Добавляем кнопку сообщить о проблеме
$(".swagger-ui").prepend(
"<div class='feedback-panel'>" +
"<button onclick='reportIssue()'>Нашли ошибку?</button>" +
"</div>"
);
});
function reportIssue() {
// Код для сбора информации и отправки отчёта
} |
|
Темная тема — не роскошь, а необходимость для многих разработчиков. NSwag позволяет реализовать переключение тем без особого труда:
CSS | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| /* custom-styles.css */
body.dark-theme {
--header-bg: #1e2329;
--header-font-color: #ffffff;
--main-bg: #2a2e33;
--code-bg: #16191d;
/* и т.д. */
}
.theme-toggle {
position: absolute;
right: 20px;
top: 20px;
} |
|
Отдельного упоминания заслуживает возможность создания мультибрендовой документации. Если ваше API обслуживает несколько клиентов с разными брендами, можно динамически менять стиль в зависимости от домена или параметров:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| app.UseSwaggerUi3(options =>
{
var host = context.Request.Host.Host;
if (host.Contains("client-a"))
{
options.CustomStylesheets.Add("./client-a-style.css");
options.CustomLogo = "client-a-logo.png";
}
else if (host.Contains("client-b"))
{
options.CustomStylesheets.Add("./client-b-style.css");
options.CustomLogo = "client-b-logo.png";
}
}); |
|
Не забываем про доступность интерфейса. NSwag позволяет улучшить UX для людей с ограниченными возможностями, добавляя спцифичные стили и ARIA-атрибуты.
Автоматическое тестирование API на основе NSwag-описания
Тестирование API — та ещё головная боль для разработчиков. Ручное написание тестов для каждого эндпоинта отнимает уйму времени, а изменения в контрактах API требуют постоянного обновления тестов. NSwag предлагает элегантное решение: автоматическое тестирование на основе OpenAPI-спецификации. Ключевая идея заключается в том, что вы можете сгенерировать тесты из того же описания, которое используется для документации. Это гарантирует, что тесты всегда соответствуют актуальному состоянию API.
C# | 1
2
3
4
5
6
7
8
9
10
| // Создаём тесты на основе OpenAPI спецификации
var document = await OpenApiDocument.FromUrlAsync("https://api.example.com/swagger/v1/swagger.json");
var apiTester = new ApiTester(document);
// Автоматически генерируем и выполняем тесты для всех GET-эндпоинтов
var results = await apiTester.TestGetEndpointsAsync(new ApiTestSettings {
BaseUrl = "https://api.example.com",
ExpectedStatusCode = 200,
AuthToken = "your-auth-token-here"
}); |
|
Для более сложных сценариев можно комбинировать NSwag с библиотеками вроде AutoFixture для генерации тестовых данных:
C# | 1
2
3
4
5
6
7
8
9
| var fixture = new Fixture();
fixture.Customize(new AutoNSubstituteCustomization());
// Генерируем тестовые данные на основе схемы из OpenAPI
var testData = fixture.Create<CreateUserRequest>();
testData.Email = "test@example.com"; // Переопределяем при необходимости
// Выполняем тест POST эндпоинта с сгенерированными данными
var result = await apiTester.TestPostEndpointAsync("/api/users", testData); |
|
Особо ценна возможность интегрировать такие тесты в CI/CD пайплайн. Представьте: при каждом пуше код собирается, развёртывается во временное окружение, и сгенерированные тесты автоматически проверяют корректность всех API-контрактов. В моей практике был случай, когда такой подход помог обнаружить неочевидную регрессию: разработчик изменил возвращаемую модель, сохранив тот же статус-код, но автоматические тесты на основе NSwag мгновенно выявили несоответствие контракту.
Для тестирования защищенных эндпоинтов NSwag позволяет эмулировать разные авторизационные контексты:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
| // Тестирование с разными ролями пользователей
foreach (var role in new[] { "user", "admin", "manager" })
{
var token = authService.GetTokenForRole(role);
var roleResults = await apiTester.TestAllEndpointsAsync(
new ApiTestSettings { AuthToken = token });
// Проверяем, что эндпоинты доступны согласно ролям
Assert.True(roleResults
.Where(r => r.Path.Contains("/admin/"))
.All(r => role == "admin" ? r.IsSuccessful : r.StatusCode == 403));
} |
|
Тестирование граничных случаев тоже можно автоматизировать, "оцифровывая" ваш ручной QA. NSwag может проверить все эндпоинты на корректную обработку ошибок, валидацию и обработку граничных значений.
Сгенерированые на основе NSwag тесты — не замена для юнит-тестов или интеграционных тестов, а дополнительный слой проверки контрактной целостности API. Это отличный способ убедиться, что документация всегда синхронизирована с реальным поведением системы.
Механизмы документирования авторизации и аутентификации в NSwag
Документирование механизмов безопасности – одна из самых недооценённых, но критически важных частей API-документации. NSwag предлагает мощный и гибкий функционал для описания различных схем авторизации, что делает работу с защищенными API гораздо более прозрачной и удобной. Начнём с основных типов безопасности, которые поддерживает NSwag: Basic Auth, API Key, OAuth 2.0 и JWT. Настройка схем безопасности производится при конфигурации OpenAPI-документа:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| services.AddOpenApiDocument(options => {
// Базовая аутентификация
options.AddSecurity("basic", new OpenApiSecurityScheme {
Type = OpenApiSecuritySchemeType.Basic,
Description = "Basic auth"
});
// API ключ
options.AddSecurity("apiKey", new OpenApiSecurityScheme {
Type = OpenApiSecuritySchemeType.ApiKey,
Name = "X-API-Key",
In = OpenApiSecurityApiKeyLocation.Header,
Description = "API ключ для доступа к защищеным эндпоинтам"
});
// JWT токен
options.AddSecurity("jwt", new OpenApiSecurityScheme {
Type = OpenApiSecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT",
Description = "JWT Authorization header. Пример: 'Bearer {token}'"
});
}); |
|
Мощь NSwag проявляется при работе с OAuth 2.0. Можно детально настроить OAuth-потоки, включая auth code, implicit, password и client credentials:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
| options.AddSecurity("oauth2", new OpenApiSecurityScheme {
Type = OpenApiSecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows {
AuthorizationCode = new OpenApiOAuthFlow {
AuthorizationUrl = new Uri("https://auth.example.com/connect/authorize"),
TokenUrl = new Uri("https://auth.example.com/connect/token"),
Scopes = new Dictionary<string, string> {
{ "api:read", "Чтение данных" },
{ "api:write", "Запись данных" }
}
}
}
}); |
|
Для применения схем безопасности к конкретным операциям можно использовать атрибуты в контроллерах или специальные процессоры операций:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| options.OperationProcessors.Add(new OperationSecurityProcessor("jwt"));
// Или избирательно для конкретных операций
options.OperationProcessors.Add(new OperationSecuritySelectorProcessor(
(operation, context) => {
// Применяем JWT только к операциям с тегом "secured"
if (operation.Tags.Contains("secured")) {
operation.Security.Add(new OpenApiSecurityRequirement {
{ new OpenApiSecurityScheme { Reference = new OpenApiReference {
Id = "jwt", Type = ReferenceType.SecurityScheme } }, new string[] { } }
});
}
return true;
}
)); |
|
NSwag также умеет интегрировать схемы авторизации с реальными политиками в вашем API — достаточно использовать фильтр обработки документации:
C# | 1
2
3
4
5
6
7
| options.OperationProcessors.Add(new AspNetCoreOperationSecurityProcessor(
provider =>
{
var policyProvider = provider.GetRequiredService<IAuthorizationPolicyProvider>();
return policyProvider;
}
)); |
|
На практике я столкнулся с интересной особенностью: не всегда нужно раскрывать все детали авторизации в публичной документаци. NSwag позволяет настраивать отображение информации о безопасности в зависимости от того, кто просматривает документацию:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // Разная документация для разных ролей
app.UseSwaggerUi3(settings => {
if (User.IsInRole("Developer")) {
settings.OAuth2Client = new OAuth2ClientSettings {
ClientId = "dev-client",
AppName = "Developer Portal",
UsePkceWithAuthorizationCodeGrant = true
};
} else {
settings.OAuth2Client = new OAuth2ClientSettings {
ClientId = "external-client",
AppName = "API Portal"
};
}
}); |
|
Для многих команд, с которыми я работал, именно удобство тестирования защищенных эндпоинтов стало решающим фактором в пользу NSwag. Особено ценно, что можно сохранять токены между сеансами и автоматически применять их к запросам.
ReDoc: элегантное решение для документации API
ReDoc – одно из самых стильных и функциональных решений для визуализации OpenAPI-спецификаций. Если Swagger UI кажется слишком техническим и перегруженным, а вы мечтаете о документации, которую не стыдно показать клиентам – ReDoc станет идеальным выбором. Главное преимущество ReDoc – интуитивно понятный, современный интерфейс. Вместо традиционного подхода с аккордеоном, ReDoc использует трёхколоночный макет: навигация слева, описание эндпоинтов посередине и схемы данных справа. Такая структура значительно упрощает навигацию по сложным API.
ReDoc можно использовать как standalone-решение, вместо Swagger UI, или интегрировать его с NSwag. Для базовой настройки в .NET 9 необходимо выполнить несколько простых шагов:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
| // Устанавливаем пакет
dotnet add package Redoc.AspNetCore
// Регистрируем в Program.cs
builder.Services.AddOpenApi(); // Стандартная генерация OpenAPI для .NET 9
// Добавляем ReDoc UI
app.UseReDoc(options =>
{
options.SpecUrl = "/openapi/v1.json"; // Путь к OpenAPI спецификации
options.RoutePrefix = "docs"; // ReDoc будет доступен по адресу /docs
options.DocumentTitle = "API Reference";
}); |
|
Если вы по-прежнему используете .NET 8 и ниже с Swashbuckle, то интеграция тоже проста:
C# | 1
2
3
4
5
6
7
| app.UseReDoc(options =>
{
options.SpecUrl = "/swagger/v1/swagger.json";
options.RoutePrefix = "api-docs";
options.HideDownloadButton = true; // Скрываем кнопку скачивания JSON
options.HideHostname = false; // Показываем имя хоста
}); |
|
Одна из самых мощных фишек ReDoc – поддержка расширенной разметки Markdown для описаний. Вы можете использовать форматирование, списки, таблицы, и даже вставлять изображения:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| /// <summary>
/// Получает список транзакций для указанного аккаунта.
///
/// ## Примечания
///
/// * Транзакции возвращаются в обратном хронологическом порядке
/// * Поддерживается пагинация через параметры [INLINE]page[/INLINE] и [INLINE]pageSize[/INLINE]
///
/// 
/// </summary>
[HttpGet("accounts/{accountId}/transactions")]
public async Task<ActionResult<PaginatedResult<Transaction>>> GetTransactions(
[Description("ID аккаунта")] string accountId)
{
// ...
} |
|
Результат превосходит ожидания – документация выглядит профессионально и понятно даже для неразработчиков. Это особено важно, когда API используется партнёрами или клиентами вашей компании.
ReDoc поддерживает темизацию через настройку цветов, шрифтов и других стилевых элементов. Для брендирования документации под фирменный стиль компании:
C# | 1
2
3
4
5
6
7
8
| app.UseReDoc(options =>
{
options.SpecUrl = "/openapi/v1.json";
options.Theme.Colors.Primary = "#32329f"; // Основной цвет
options.Theme.Typography.FontFamily = "Roboto, sans-serif";
options.Theme.Typography.HeadingsFont = "Montserrat, sans-serif";
options.Theme.Logo.Gutter = "20px"; // Отступ для логотипа
}); |
|
Для более глубокой кастомизации можно использовать CDN-хостинг с настройками:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| app.UseReDoc(options =>
{
options.SpecUrl = "/openapi/v1.json";
options.RoutePrefix = "api-docs";
// Использование внешнего CDN для скриптов ReDoc
options.UseReDocProSettings = true; // Включаем Pro-версию (если есть лицензия)
options.ConfigureReDoc = reDoc =>
{
reDoc.HideHostname = false;
reDoc.PathInMiddlePanel = true;
reDoc.RequiredPropsFirst = true;
reDoc.SortPropsAlphabetically = true;
};
// Полный контроль через HTML
options.IndexStream = () =>
new FileStream("./ReDocIndex.html", FileMode.Open);
}); |
|
Отдельного внимания заслуживает поддержка тегов и их группировка в ReDoc. В отличие от Swagger UI, где теги просто разделяют операции, ReDoc позволяет создавать иерархии тегов, объединять их в группы:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // В OpenAPI спецификации
options.AddDocumentProcessor(document =>
{
document.Tags = new List<OpenApiTag>
{
new OpenApiTag { Name = "Accounts", Description = "Операции с аккаунтами" },
new OpenApiTag { Name = "Transactions", Description = "Платежи и переводы" },
new OpenApiTag
{
Name = "Reports",
Description = "Отчеты и аналитика",
// Группировка тегов в ReDoc
"x-displayName": "Аналитический блок"
}
};
}); |
|
В процессе работы над API для крупного ecommerce-проекта мы столкнулись с проблемой — наше API имело более 200 эндпоинтов в 15 разных доменных областях. Swagger UI превращался в бесконечный список, в котором легко было потеряться. ReDoc с группировкой и гибкой навигацией моментально упростил работу с документацией.
Ещё одна привлекательная особенность ReDoc — автоматическое создание оглавления и возможность закрепления сайдбара для удобной навигации. Для больших API это неоценимо:
C# | 1
2
3
4
5
6
7
8
9
10
| app.UseReDoc(options =>
{
options.SpecUrl = "/openapi/v1.json";
options.Theme.SideBar.Width = "300px";
options.Theme.SideBar.BackgroundColor = "#fafafa";
options.Theme.SideBar.TextColor = "#333333";
// Закрепить сайдбар при скроллинге
options.UseFixedSidebar = true;
}); |
|
ReDoc также поддерживает расширенные возможности для отображения аутентификации и авторизации. Схемы безопасности отображаются наглядно, с поддержкой интерактивного ввода учетных данных:
C# | 1
2
3
| // Настройка отображения OAuth2 в ReDoc
options.OAuth2RedirectUrl = "https://api.example.com/oauth2-redirect.html";
options.OAuth2Callback = "function onOAuthComplete(token) { console.log('Got token:', token); }"; |
|
Реализация интерактивных примеров запросов в ReDoc
ReDoc вовсе не ограничивается статичным отображением документации — с правильной настройкой вы можете добавить интерактивные примеры запросов, что превращает его в полноценную среду для тестирования API. Это особенно ценно, когда нужно предоставить документацию, которую можно не только читать, но и использовать для экспериментов.
Первый шаг — добавление примеров запросов и ответов в OpenAPI-спецификацию. ReDoc отлично отображает эти примеры, делая документацию более наглядной:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| // В контроллере или обработчике минимального API
/// <summary>
/// Создает нового пользователя
/// </summary>
/// <remarks>
/// Sample request:
///
/// POST /api/users
/// {
/// "username": "johndoe",
/// "email": "john@example.com",
/// "firstName": "John",
/// "lastName": "Doe"
/// }
///
/// </remarks>
[HttpPost]
[Produces("application/json")]
[ProducesResponseType(typeof(UserResponse), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateUser([FromBody] CreateUserRequest request)
{
// ...
} |
|
ReDoc автоматически преобразует такие примеры в интерактивные блоки с синтаксической подсветкой. Но можно пойти дальше, добавив возможность выполнения запросов прямо из документации. Для этого используется расширение ReDoc с Try-It-Out функциональностью:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| app.UseReDoc(options =>
{
options.SpecUrl = "/openapi/v1.json";
options.RoutePrefix = "docs";
// Включаем интерактивные запросы
options.EnableTryItOut = true;
options.TryItOutConfig = new TryItOutConfig
{
// Настройки для Try-It-Out
EnableRequestPayloadValidation = true,
EnableResponseValidation = true,
DefaultExpandResponses = "200,201", // Автоматически раскрываем успешные ответы
};
}); |
|
Для более сложных сценариев можно добавить интеграцию с популярными HTTP-клиентами, позволяя пользователям экспортировать запросы в Postman, cURL, HTTPie или другие инструменты:
C# | 1
2
3
4
5
6
7
| // Добавляем экспорт запросов в различные форматы
options.EnableRequestExamples = true;
options.RequestExamplesConfig = new RequestExamplesConfig
{
AvailableFormats = new[] { "curl", "postman", "httpie" },
DefaultFormat = "curl"
}; |
|
Особенно полезной фишкой является возможность включать несколько примеров для одного эндпоинта, демонстрируя различные сценарии использования. ReDoc красиво группирует их с возможностью переключения:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| // Добавляем несколько примеров к операции
options.AddDocumentProcessor(document =>
{
var createUserOperation = document.Paths["/api/users"]
.Operations[OpenApiOperationType.Post];
createUserOperation.RequestBody.Content["application/json"].Examples
= new Dictionary<string, OpenApiExample>
{
["basic"] = new OpenApiExample
{
Summary = "Базовый пример",
Value = new { username = "user1", email = "user@example.com" }
},
["complete"] = new OpenApiExample
{
Summary = "Полный пример",
Value = new {
username = "johndoe",
email = "john@example.com",
firstName = "John",
lastName = "Doe",
settings = new {
theme = "dark",
notifications = true
}
}
}
};
}); |
|
На нашем проекте финтех-маркетплейса я реализовал динамическое добавление примеров запросов на основе реальных тестовых данных. Это существенно упростило интеграцию для наших партнёров — они видели именно те форматы данных, с которыми им предстояло работать в реальности.
Еще одно практическое улучшение — автогенерация примеров на основе схем данных с использованием фейковых данных. Мы написали простой генератор, который создавал правдоподобные примеры на основе типов полей и их валидационных атрибутов:
C# | 1
2
3
4
5
6
7
8
| // Генератор примеров на основе схем
services.AddTransient<IOpenApiExampleGenerator, SmartExampleGenerator>();
services.AddOpenApiDocument(options =>
{
options.UseExamplesFromAttributes = true;
options.GenerateExamples = true;
options.ExampleGenerator = new SmartExampleGenerator();
}); |
|
Результатом стало то, что каждый эндпоинт в документации содержал разумные примеры данных, даже если разработчик не добавил их вручную — это ощутимо повышало качество и полноту документации.
Для локализованных API ценной особенностью является поддержка многоязычных примеров, когда вы можете предоставить варианты запросов и ответов на разных языках:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // Примеры на разных языках
createUserOperation.Responses["200"].Content["application/json"].Examples
= new Dictionary<string, OpenApiExample>
{
["en"] = new OpenApiExample
{
Summary = "English response",
Value = new { message = "User created successfully" }
},
["ru"] = new OpenApiExample
{
Summary = "Ответ на русском",
Value = new { message = "Пользователь успешно создан" }
}
}; |
|
Комбинируя все эти возможности, ReDoc превращается в полноценную интерактивную документацию, которая не только информирует, но и активно помогает разработчикам в изучении и тестировании вашего API.
Кастомизация документации ReDoc с использованием markdown и HTML
ReDoc отлично поддерживает форматирование с помощью Markdown, что открывает широкие возможности для создания богатой, структурированной документации. В отличие от Swagger UI, где форматирование обычно ограничено, ReDoc позволяет использовать полноценный Markdown с заголовками, таблицами, выделением кода и даже внедрением HTML для продвинутой кастомизации. Для начала можно добавить расширенное описание к тегам и операциям:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| options.AddDocumentProcessor(document =>
{
var paymentTag = document.Tags.FirstOrDefault(t => t.Name == "Payments");
if (paymentTag != null)
{
paymentTag.Description = @"
[H2]Платежный модуль API[/H2]
Платежный модуль позволяет:
* Создавать транзакции
* Подтверждать платежи
* Отменять транзакции
* Получать отчеты
### Процесс обработки платежа
1. Создание платежа
2. Авторизация
3. Подтверждение
4. Завершение
| Статус | Описание | Возможные действия |
|--------|----------|------------------|
| Pending | Ожидание | Confirm, Cancel |
| Confirmed | Подтвержден | Refund |
| Cancelled | Отменен | - |
";
}
}); |
|
Расширенная разметка значительно улучшает восприятие документации, добавляя структуру и визуальные элементы. ReDoc автоматически создаёт навигацию на основе заголовков Markdown, что особенно удобно для длинных описаний.
Для еще более глубокой кастомизации можно использовать встроенный HTML прямо в описаниях:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| /// <summary>
/// Получает историю транзакций
/// </summary>
/// <remarks>
/// Получает полную историю транзакций по аккаунту.
///
/// <div class="warning">
/// <strong>Внимание!</strong> Этот метод может возвращать большие объемы данных.
/// Используйте параметры пагинации.
/// </div>
///
/// <style>
/// .warning {
/// background-color: #fff8e6;
/// border-left: 4px solid #f0ad4e;
/// padding: 12px;
/// margin-bottom: 16px;
/// }
/// </style>
/// </remarks>
[HttpGet("transactions/history")]
public async Task<ActionResult<List<Transaction>>> GetTransactionHistory(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 20)
{
// реализация
} |
|
ReDoc корректно обрабатывает встроенные стили и HTML-элементы, позволяя создавать предупреждения, подсказки, заметки и другие визуальные блоки, повышающие удобочитаемость документации.
Для комплексной кастомизации можно создать полностью собственный HTML-шаблон, который будет использоваться для рендеринга ReDoc:
C# | 1
2
3
4
5
6
| app.UseReDoc(options =>
{
options.IndexStream = () => new FileStream(
Path.Combine(AppContext.BaseDirectory, "ReDocTemplate.html"),
FileMode.Open);
}); |
|
Шаблон может содержать дополнительные разделы, интерактивные элементы или специфическую для вашей компании информацию:
HTML5 | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| <!DOCTYPE html>
<html>
<head>
<title>API Документация</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,700" rel="stylesheet">
<style>
body { margin: 0; padding: 0; font-family: 'Roboto', sans-serif; }
.company-header { background: #2d5986; color: white; padding: 10px 0; text-align: center; }
.api-info { padding: 20px; background: #f8f9fa; border-bottom: 1px solid #e9ecef; }
</style>
</head>
<body>
<div class="company-header">
<img src="/logo.svg" height="40" alt="Лого компании" />
<h1>Документация API</h1>
</div>
<div class="api-info">
<p>Версия: v2.1.4 | Среда: Продакшн | Последнее обновление: 15.05.2023</p>
<p>Техническая поддержка: <a href="mailto:api-support@example.com">api-support@example.com</a></p>
</div>
<div id="redoc-container"></div>
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"></script>
<script>
Redoc.init(
'%SPEC_URL%',
{
hideDownloadButton: true,
theme: { colors: { primary: { main: '#2d5986' } } }
},
document.getElementById('redoc-container')
);
</script>
</body>
</html> |
|
В ReDoc можно также включить пользовательские скрипты для расширения функциональности документации. Например, добавить интерактивные графики для визуализации данных API или инструменты для конвертации между различными форматами:
HTML5 | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| <script>
// Добавляем кнопку "Копировать как cURL" ко всем примерам запросов
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
const examples = document.querySelectorAll('.request-samples');
examples.forEach(example => {
const button = document.createElement('button');
button.innerText = 'Копировать как cURL';
button.onclick = function() {
// Конвертация запроса в формат cURL
const code = example.querySelector('code').innerText;
navigator.clipboard.writeText(convertToCurl(code));
};
example.appendChild(button);
});
}, 1000);
});
function convertToCurl(code) {
// Логика конвертации запроса в cURL
return `curl -X POST ${extractUrl(code)} -H "Content-Type: application/json" -d '${extractBody(code)}'`;
}
</script> |
|
Важное преимущество ReDoc – возможность создания мультиверсионной документации. При разработке API с несколькими версиями это критично. Вы можете предложить пользователям переключаться между версиями документации:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // Регистрируем несколько версий OpenAPI
app.MapOpenApi("v1", options => /* настройки V1 */);
app.MapOpenApi("v2", options => /* настройки V2 */);
// ReDoc с выбором версий
app.UseReDoc(options =>
{
options.DocumentTitle = "API Reference";
options.SpecUrl = new Dictionary<string, string>
{
["v1"] = "/openapi/v1.json",
["v2"] = "/openapi/v2.json"
};
}); |
|
Важной особенностью ReDoc является встроенная поддержка поиска по документации – функция, которая отсутствует в базовой версии Swagger UI. Полнотекстовый поиск работает как по названиям эндпоинтов, так и по их описаниям и схемам, что критично для больших API:
C# | 1
2
3
4
5
6
7
| options.EnableSearch = true;
options.SearchConfig = new SearchConfig
{
FullTextSearch = true,
MinSearchChars = 3,
HighlightResults = true
}; |
|
Производительность – ещё один аспект, где ReDoc часто превосходит конкурентов. При большой OpenAPI-спецификации Swagger UI может тормозить, а ReDoc использует виртуализацию для отображения только видимых элементов, что значительно ускоряет загрузку и работу с документацией. Для серьезных API с сотнями эндпоинтов разница становится существенной.
На проекте платформы автоматизации маркетинга мы заменили Swagger UI на ReDoc и получили ощутимые преимущества: время загрузки документации сократилось на 67%, а пользователи отметили значительное улучшение читабельности и навигации. Особенно полезной оказалась возможность формирования полноценного оглавления и четкого разделения разделов документации.
Реализация интерактивных примеров запросов в ReDoc
Интерактивные примеры — это именно то, что превращает документацию из скучного справочника в полноценный инструмент разработчика. ReDoc предлагает несколько подходов к созданию действительно полезных интерактивных примеров. Самый простой способ начать — добавление атрибута [SwaggerRequestExample] к вашим эндпоинтам. Для этого потребуется установить пакет Swashbuckle.AspNetCore.Filters :
C# | 1
2
3
4
5
6
| // Устанавливаем нужный пакет
dotnet add package Swashbuckle.AspNetCore.Filters
// Добавляем поддержку примеров в Program.cs
builder.Services.AddOpenApi()
.AddSwaggerExamplesFromAssemblyOf<Program>(); |
|
После этого можно создать классы с примерами запросов:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public class CreateOrderRequestExample : IExamplesProvider<CreateOrderRequest>
{
public CreateOrderRequest GetExamples()
{
return new CreateOrderRequest
{
CustomerId = "CUST-12345",
Items = new List<OrderItem>
{
new() { ProductId = "PROD-001", Quantity = 2, UnitPrice = 19.99m },
new() { ProductId = "PROD-015", Quantity = 1, UnitPrice = 39.50m }
},
ShippingAddress = new Address
{
Street = "123 Main St",
City = "New York",
ZipCode = "10001",
Country = "USA"
},
PaymentMethod = PaymentMethod.CreditCard
};
}
} |
|
Теперь привяжем пример к нашему API-методу:
C# | 1
2
3
4
5
6
7
| [HttpPost("orders")]
[SwaggerRequestExample(typeof(CreateOrderRequest), typeof(CreateOrderRequestExample))]
[ProducesResponseType(typeof(OrderCreatedResponse), StatusCodes.Status201Created)]
public async Task<IActionResult> CreateOrder([FromBody] CreateOrderRequest request)
{
// Реализация
} |
|
Что действительно круто в ReDoc, так это возможность задавать множественные примеры для одного эндпоинта. Представьте, что у вас есть API для обработки платежей — логично показать несколько сценариев: обычная покупка, подписка, возврат средств.
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // В OpenAPI-спецификации можем добавить сразу несколько примеров
document.Paths["/api/payments"]
.Operations[OpenApiOperationType.Post]
.RequestBody.Content["application/json"].Examples = new Dictionary<string, OpenApiExample>
{
["simple-purchase"] = new OpenApiExample
{
Summary = "Простая покупка",
Value = new { amount = 9.99, currency = "USD", paymentMethod = "card" }
},
["subscription"] = new OpenApiExample
{
Summary = "Подписка",
Value = new { amount = 15.99, currency = "EUR", paymentMethod = "card", recurring = true, period = "monthly" }
}
}; |
|
На нашем последнем проекте я внедрил динамические примеры, которые генерировались на основе реальных данных в тестовом окружении. Это дало возможность клиентам видеть не абстрактные, а максимально приближенные к реальности примеры:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| public class DynamicExampleProvider : IRequestExampleProvider
{
private readonly ITestDatabaseService _testDb;
public DynamicExampleProvider(ITestDatabaseService testDb)
{
_testDb = testDb;
}
public async Task<object> GetExampleAsync(Type requestType, string operationId)
{
if (operationId == "CreateOrder")
{
// Получаем последний реальный заказ из тестовой базы
var lastOrder = await _testDb.GetLastOrderAsync();
return new CreateOrderRequest
{
// Преобразуем в формат запроса
// ...
};
}
return null; // Для других операций используем стандартные примеры
}
} |
|
Чтобы сделать примеры по-настоящему интерактивными, можно добавить функциональность Try-It-Out с помощью JavaScript. В отличие от базового ReDoc, где примеры статичны, такой подход позволяет пользователям модифицировать запрос и отправлять его прямо из документации:
JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| // Добавляем кнопку для выполнения запроса под каждым примером
document.querySelectorAll('.request-example').forEach(example => {
const execButton = document.createElement('button');
execButton.innerText = 'Выполнить запрос';
execButton.className = 'try-it-button';
execButton.addEventListener('click', async () => {
const codeBlock = example.querySelector('code');
const requestData = JSON.parse(codeBlock.textContent);
// Получаем URL из контекста примера
const url = example.closest('.operation-block').dataset.path;
// Выполняем запрос и показываем результат
try {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestData)
});
// Отображаем результат под примером
const resultBlock = document.createElement('div');
resultBlock.className = 'response-block';
resultBlock.innerHTML = `<h4>Ответ (${response.status}):</h4>
<pre><code>${JSON.stringify(await response.json(), null, 2)}</code></pre>`;
// Добавляем или обновляем блок с результатом
const existingResult = example.querySelector('.response-block');
if (existingResult) example.removeChild(existingResult);
example.appendChild(resultBlock);
} catch (error) {
console.error('Ошибка выполнения запроса:', error);
}
});
example.appendChild(execButton);
}); |
|
Кастомизация документации ReDoc с использованием markdown и HTML
Возможности кастомизации ReDoc идут гораздо дальше простых настроек цветов и шрифтов. Используя продвинутые возможности Markdown и HTML-разметки, можно превратить скучную техническую документацию в наглядное пособие, которое понравится даже не-техническим специалистам.
Один из моих любимых приёмов – использование сворачиваемых секций для группировки связанной информации. Это особенно полезно для объёмных описаний, где не хочется перегружать пользователя всей информацией сразу:
HTML5 | 1
2
3
4
5
6
7
8
9
10
11
| <details>
<summary>Расширенная информация о параметрах платежа</summary>
### Поля для международных платежей
- [INLINE]swift[/INLINE] - SWIFT-код банка получателя
- [INLINE]iban[/INLINE] - международный номер счета
- [INLINE]purpose[/INLINE] - назначение платежа
### Налоговая информация
Для платежей свыше €1000 требуется указать налоговый идентификатор.
</details> |
|
Такой подход позволяет скрыть детальную информацию, показывая её только тем пользователям, которым она действительно нужна.
Еще одна полезная техника – создание вкладок для отображения примеров на разных языках программирования:
HTML5 | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| <div class="code-tabs">
<button class="tab-button active" onclick="showTab('csharp')">C#</button>
<button class="tab-button" onclick="showTab('typescript')">TypeScript</button>
<div id="csharp" class="tab-content active">
<pre><code>
var client = new HttpClient();
var response = await client.GetAsync("https://api.example.com/users");
var users = await response.Content.ReadFromJsonAsync<List<User>>();
</code></pre>
</div>
<div id="typescript" class="tab-content">
<pre><code>
const response = await fetch('https://api.example.com/users');
const users = await response.json();
</code></pre>
</div>
</div>
<style>
.code-tabs { border: 1px solid #ddd; border-radius: 4px; overflow: hidden; }
.tab-button { background: #f5f5f5; border: none; padding: 8px 16px; cursor: pointer; }
.tab-button.active { background: #fff; border-bottom: 2px solid #3f51b5; }
.tab-content { display: none; padding: 16px; }
.tab-content.active { display: block; }
</style>
<script>
function showTab(id) {
document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.tab-button').forEach(b => b.classList.remove('active'));
document.getElementById(id).classList.add('active');
document.querySelector(`button[onclick="showTab('${id}')"]`).classList.add('active');
}
</script> |
|
При работе над API платёжной системы я столкнулся с необходимостью визуализировать сложные процессы обработки транзакций. Текстового описания было явно недостаточно. Решение пришло в виде встраиваемых SVG-диаграмм:
HTML5 | 1
2
3
4
5
6
7
8
9
10
11
| <div class="flow-diagram">
<svg width="600" height="200">
<rect x="10" y="50" width="120" height="60" rx="8" fill="#e3f2fd" stroke="#2196f3" />
<text x="70" y="80" text-anchor="middle">Создание платежа</text>
<polygon points="140,80 160,70 160,90" fill="#2196f3" />
<line x1="130" y1="80" x2="160" y2="80" stroke="#2196f3" stroke-width="2" />
<!-- Остальные элементы диаграммы -->
</svg>
</div> |
|
Исключительно мощный приём – создание кастомных информационных блоков. Это помогает визуально выделять важную информацию, предупреждения или советы:
HTML5 | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| <div class="info-box warning">
<h4>Внимание!</h4>
<p>Этот эндпоинт будет объявлен устаревшим в версии 3.0. Используйте новый метод <code>/api/v2/profile</code>.</p>
</div>
<style>
.info-box {
padding: 15px;
margin: 20px 0;
border-radius: 4px;
border-left: 4px solid;
}
.info-box.warning {
background-color: #fff3e0;
border-left-color: #ff9800;
}
.info-box h4 {
margin-top: 0;
color: #ff9800;
}
</style> |
|
Стратегии версионирования API в ReDoc
Версионирование API — одна из самых непростых задач, с которой сталкивается каждый разработчик. Как заменить двигатель самолёта в полёте, не уронив его? Примерно так можно описать процесс обновления API без нарушения работы существующих клиентов. ReDoc предлагает несколько элегантных решений для документирования и управления разными версиями API. Начнём с того, что ReDoc позволяет создавать отдельные спецификации для каждой версии вашего API и объединять их в общем интерфейсе:
C# | 1
2
3
4
5
6
7
8
9
10
11
| app.UseReDoc(options =>
{
options.SpecUrl = new Dictionary<string, string>
{
["v1"] = "/openapi/v1.json",
["v2"] = "/openapi/v2.json",
["v3-beta"] = "/openapi/v3-beta.json"
};
options.RoutePrefix = "docs";
options.DocumentTitle = "API Reference";
}); |
|
Что действительно круто, это возможность настроить переключатель версий, который позволяет пользователям легко переходить между разными версиями документации. В сочетании с цветовой маркировкой для разных версий это создаёт интуитивно понятный интерфейс:
C# | 1
2
3
4
5
6
7
8
9
10
| options.ConfigureRedoc(redoc =>
{
redoc.VersionSwitcher = true;
redoc.VersionColors = new Dictionary<string, string>
{
["v1"] = "#9e9e9e", // Серый для устаревшей версии
["v2"] = "#4caf50", // Зелёный для текущей стабильной версии
["v3-beta"] = "#ff9800" // Оранжевый для бета-версии
};
}); |
|
На практике я использую три основных стратегии версионирования в ReDoc:
1. Подход "одна спецификация — много версий" — все версии API включаются в единую спецификацию с соответствующими тегами. Это удобно для небольших API с несколькими версиями.
2. Мультиспецификация — отдельные OpenAPI-документы для каждой версии API. Идеально для крупных API с существенными различиями между версиями.
3. Гибридный подход — основная спецификация содержит последнюю версию, а исторические версии хранятся отдельно, с чётким указанием устаревших эндпоинтов.
Для маркировки устаревших эндпоинтов в ReDoc можно использовать расширение OpenAPI:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| options.AddOperationFilter<DeprecatedOperationFilter>();
// Фильтр, который помечает устаревшие эндпоинты
public class DeprecatedOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var apiVersion = context.ApiDescription.ActionDescriptor.EndpointMetadata
.OfType<ApiVersionAttribute>()
.FirstOrDefault();
if (apiVersion?.Deprecated == true)
{
operation.Deprecated = true;
operation.Description = $" [B]Устарело с версии {apiVersion.Version}[/B]\n\n{operation.Description}";
}
}
} |
|
ReDoc отлично подчёркивает устаревшие операции, выделяя их визуально и добавляя соответствующие предупреждения — пользователи сразу видят, какие эндпоинты не стоит использовать в новых разработках.
Организация документирования сложных моделей данных в ReDoc
Работа со сложными моделями данных — это один из тех аспектов API-документации, где ReDoc действительно блистает. Когда ваши модели содержат вложенные объекты, коллекции, полиморфные типы и рекурсивные структуры, стандартный подход Swagger UI начинает откровенно хромать. В таких случаях ReDoc предлагает целый арсенал инструментов и подходов.
Одно из золотых правил, которые я вынес из опыта документирования финансовых API — разделяй и властвуй. ReDoc позволяет структурировать вложенные модели с помощью закодированной в OpenAPI схемы allOf , oneOf и anyOf :
C# | 1
2
3
4
5
6
7
8
9
10
11
12
| // Пример полиморфной модели с использованием oneOf
document.Components.Schemas["PaymentMethod"] = new OpenApiSchema
{
OneOf = new List<OpenApiSchema>
{
new OpenApiSchema { Reference = new OpenApiReference {
Id = "CreditCardPayment", Type = ReferenceType.Schema } },
new OpenApiSchema { Reference = new OpenApiReference {
Id = "BankTransferPayment", Type = ReferenceType.Schema } }
},
Description = "Способ оплаты, который может быть либо кредитной картой, либо банковским переводом"
}; |
|
ReDoc визуализирует такие случаи намного лучше, чем Swagger, показывая интерактивное переключение между вариантами и наглядно демонстрируя структуру каждого подтипа.
Для рекурсивных моделей (например, каталогов с дочерними категориями) ReDoc предлагает элегантное решение — ограничение глубины отображения с возможностью "раскрыть дальше":
C# | 1
| options.SchemaSettings.MaxRecursiveDepth = 2; // Показывать рекурсию только на 2 уровня |
|
Другой мощный приём — использование дискриминатора для моделей с наследованием. Это позволяет ReDoc автоматически определять и отображать конкретный тип сущности:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // Пример базовой модели с дискриминатором
document.Components.Schemas["Vehicle"] = new OpenApiSchema
{
Properties = new Dictionary<string, OpenApiSchema>
{
["type"] = new OpenApiSchema { Type = "string", Description = "Тип транспортного средства" }
},
Discriminator = new OpenApiDiscriminator
{
PropertyName = "type",
Mapping = new Dictionary<string, string>
{
["car"] = "#/components/schemas/Car",
["motorcycle"] = "#/components/schemas/Motorcycle"
}
}
}; |
|
Stoplight: комплексная платформа для API-дизайна
Если ReDoc и NSwag решают конкретные задачи документирования и интеграции API, то Stoplight представляет собой принципиально иной подход — это полноценная экосистема для работы с API на всех этапах жизненного цикла. Можно сказать, что Stoplight для API — как IDE для кода. В отличие от предыдущих решений, Stoplight ориентирован на подход "API-First" (сначала API, потом код), где разработка начинается с дизайна интерфейсов. Это позволяет командам согласовать контракты до написания первой строчки кода, что значительно снижает количество переделок и конфликтов.
Ключевая особенность Stoplight — визуальный редактор API. Он позволяет создавать OpenAPI-спецификации без знания синтаксиса JSON или YAML, что делает процесс доступным не только разработчикам, но и продакт-менеджерам, техническим писателям и даже представителям бизнеса.
Bash | 1
2
3
4
5
| # Установка Stoplight Studio локально через NPM
npm install -g @stoplight/studio-cli
# Запуск Stoplight Studio
stoplight studio |
|
Инструмент Stoplight Studio даёт возможность прототипировать API, создавать и тестировать моки (имитации) API без написания серверной части. Это позволяет фронтенд-разработчикам начать работу задолго до готовности бэкенда:
Bash | 1
2
| # Создание мок-сервера на основе спецификации OpenAPI
npx @stoplight/prism-cli mock -p 4010 openapi.yaml |
|
Коллаборативные возможности платформы впечатляют. Stoplight обеспечивает общую среду для всех участников проекта: разработчиков, тестировщиков, техписателей и менеджеров. Изменения документации происходят в режиме реального времени, с системой контроля версий и комментирования.
"На одном проекте мы внедрили Stoplight и сократили время на согласование изменений API между командами на 70%. Больше никаких бесконечных email-цепочек с замечаниями к спецификации," — делился со мной коллега, техлид в крупном банке.
Интеграция Stoplight с Git означает, что ваши спецификации хранятся вместе с кодом и проходят те же процедуры ревью. Это обеспечивает синхронизацию документации и реального поведения API, помогая избежать классической проблемы, когда документация оторвана от реальности. Хаб API — еще одна мощная фишка Stoplight. Он предоставляет централизованное хранилище для всех API вашей организации, создавая единую точку доступа к документации, независимо от того, сколько у вас микросервисов и команд:
JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // Пример конфигурации для интеграции Stoplight Hub с аутентификацией
{
"projects": [
{
"name": "Payment API",
"path": "./payment-api",
"visibility": "internal"
},
{
"name": "Customer API",
"path": "./customer-api",
"visibility": "public"
}
],
"auth": {
"provider": "oauth2",
"config": {
"authority": "https://auth.example.com",
"clientId": "stoplight-hub"
}
}
} |
|
Для разработчиков .NET особенно ценна тесная интеграция Stoplight с различными фреймворками. Можно экспортировать спецификации из Stoplight и интегрировать их в ASP.NET Core проекты, даже если основа вашего API изначально разрабатывалась без кода:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // Подключение Stoplight-сгенерированной спецификации к ASP.NET Core
app.UseOpenApi(options => {
options.DocumentName = "v1";
options.Path = "/api-docs/v1.json";
options.SerializeAsV2 = false; // Используем OpenAPI 3.0
});
// Использование документации из Stoplight в ASP.NET Core проекте
app.UseReDoc(options => {
options.SpecUrl = "/stoplight-spec.json";
options.RoutePrefix = "docs";
options.DocumentTitle = "API Docs";
// Можно подключить стили из Stoplight
options.Theme.Fonts.MonoFont = "Roboto Mono, monospace";
}); |
|
Валидация API – еще одна сильная сторона Stoplight. Встроенные линтеры автоматически проверяют спецификации на соответствие лучшим практикам и корпоративным стандартам. Например, можно настроить правила именования эндпоинтов, обязательные поля в ответах или структуру версионирования:
JSON | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| // spectral.yml - конфигурация линтера Stoplight
{
"extends": ["spectral:oas", "spectral:asyncapi"],
"rules": {
"operation-tags": {
"description": "Каждая операция должна иметь хотя бы один тег",
"severity": "error",
"given": "$.paths[*][*]",
"then": {
"field": "tags",
"function": "truthy"
}
},
"pascal-case-models": {
"description": "Модели должны быть в PascalCase",
"severity": "warn",
"given": "$.components.schemas.*~",
"then": {
"function": "pattern",
"functionOptions": {
"match": "^[A-Z][a-zA-Z0-9]*$"
}
}
}
}
} |
|
В работе с микросервисной архитектурой Stoplight просто незаменим. На нашем последнем проекте с 15+ микросервисами только Stoplight смог дать четкую картину всех API интерфейсов. Функция "Dependency Graph" наглядно показывает связи между сервисами через их API, что крайне полезно для выявления потенциальных проблем при изменениях.
"Когда мы решили изменить схему аутентификации в одном из сервисов, Stoplight тут же показал нам восемь зависимых сервисов, о некоторых из которых мы даже забыли," — такое часто случается в растущих системах, не так ли?
Stoplight также предлагает расширенные возможности для автоматической генерации клиентских SDK на основе ваших спецификаций. Поддерживаются все основные языки, включая C#, TypeScript, Python и Java:
Bash | 1
2
3
4
5
| # Генерация C# клиента из спецификации Stoplight
npx @openapitools/openapi-generator-cli generate -i ./stoplight-api.yaml -g csharp -o ./csharp-client
# Генерация TypeScript клиента
npx @openapitools/openapi-generator-cli generate -i ./stoplight-api.yaml -g typescript-fetch -o ./ts-client |
|
В контексте CI/CD Stoplight предлагает API для автоматического обновления документации при изменении кода. Это позволяет настроить процесс, при котором документация всегда синхронизирована с последней версией API:
YAML | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Пример GitHub Action для обновления Stoplight при пуше
name: Update Stoplight Docs
on:
push:
branches: [ main ]
jobs:
update-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Push to Stoplight
uses: stoplightio/spectral-action@v0.8.1
with:
file_glob: 'api/*.{json,yml,yaml}'
repo_token: ${{ secrets.GITHUB_TOKEN }}
spectral_ruleset: '.spectral.yml' |
|
Инструменты моделирования API в Stoplight и визуальный дизайн
Визуальное моделирование — это именно то, что выгодно отличает Stoplight от других решений. В отличие от текстовых редакторов YAML/JSON, Stoplight Studio предлагает интуитивно понятный графический интерфейс, который полностью абстрагирует разработчика от синтаксических тонкостей спецификации OpenAPI. Представьте себе конструктор Lego для API — вот что такое Stoplight Studio. Вместо написания сотен строк спецификации вы просто перетаскиваете блоки, настраиваете их свойства и соединяете между собой. Это ворота в мир API-дизайна для людей без глубоких технических знаний. Особое внимание заслуживает моделирование схем данных в Stoplight. Создание сложных моделей с вложенными объектами, массивами и связями становится интуитивно понятным даже для тех, кто никогда не работал с OpenAPI:
JSON | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // Схема создаётся автоматически при визуальном моделировании
{
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid" },
"name": { "type": "string", "minLength": 2 },
"status": {
"type": "string",
"enum": ["active", "suspended", "deleted"]
},
"items": {
"type": "array",
"items": { "$ref": "#/components/schemas/OrderItem" }
}
},
"required": ["name", "items"]
} |
|
Всю эту структуру можно создать буквально за пару минут, перетаскивая поля и настраивая их свойства в визуальном редакторе.
Из личного опыта — визуальный дизайн API кардинально меняет процесс согласования контрактов. На одном из наших проектов по разработке маркетплейса, мы собрали бизнес-аналитиков, фронтенд и бэкенд-команды в одной комнате. Вместо недель согласований и бесконечных правок текстовых спецификаций, ушло всего два дня на то, чтобы визуально спроектировать все эндпоинты и модели данных.
Stoplight Studio позволяет мгновенно видеть результаты своей работы через функцию предпросмотра документации. По сути, вы получаете WYSIWYG-редактор для API - what you see is what you get. Изменили параметр? Тут же видите, как это отразится в документации. Редактор схем данных заслуживает отдельной похвалы. Он автоматически предлагает типы данных, форматы и валидационные правила, что заметно снижает количество ошибок при проектировании. Когда я впервые перешёл с ручного редактирования YAML на Stoplight, количество ошибок в API-контрактах уменшилось примерно на 80%.
Интеграция Stoplight с CI/CD пайплайнами для автоматической генерации документации
Одно из главных преимуществ Stoplight — возможность его бесшовной интеграции в существующие CI/CD пайплайны. Это критически важно для команд, работающих в методологии непрерывной поставки, где ручное обновление документации становится непозволительной роскошью и потенциальным источником рассинхронизации. Интеграция со Stoplight позволяет автоматически генерировать или обновлять документацию API при каждом изменении кода. Это гарантирует, что документация всегда соответствует актуальному состоянию API — проблема, с которой я сталкивался десятки раз на разных проектах.
GitHub Actions предоставляет простой способ интеграции с экосистемой Stoplight:
YAML | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| name: Build and Publish API Docs
on:
push:
branches: [ main ]
paths:
- 'src/Api/**'
- '.github/workflows/api-docs.yml'
jobs:
publish-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Generate OpenAPI Spec
run: |
dotnet build
dotnet run --project src/Api/Generator/ApiSpecGenerator.csproj \
--output ./api-spec.json
- name: Publish to Stoplight
uses: stoplightio/spectral-action@v0.8.2
with:
file_glob: 'api-spec.json'
spectral_ruleset: '.spectral.yml'
repo_token: ${{ secrets.STOPLIGHT_TOKEN }}
publish_to_stoplight: true
stoplight_project_id: ${{ secrets.STOPLIGHT_PROJECT_ID }} |
|
В Azure DevOps пайплайнах подход похож, но имеет некоторые особенности:
YAML | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| trigger:
branches:
include:
- main
paths:
include:
- src/Api/*
pool:
vmImage: 'ubuntu-latest'
steps:
task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '7.0.x'
script: |
dotnet build
dotnet run --project src/Api/OpenApiGenerator.csproj
displayName: 'Generate API Spec'
task: PublishBuildArtifacts@1
inputs:
pathtoPublish: 'api-docs.json'
artifactName: 'APISpecification'
script: |
npm install -g @stoplight/cli
stoplight publish --token $(StoplightToken) --project-id $(StoplightProjectId) api-docs.json
displayName: 'Publish to Stoplight' |
|
Я помню случай с корпоративным проектом, где из-за рассогласования документации и кода у нас случился 4-часовой простой интеграций. После внедрения автоматизации через Stoplight подобные инциденты ушли в прошлое — изменение API автоматически обновляет документацию.
Для сложных экосистем микросервисов можно настроить централизованное обновление документации всех API. В этом случае каждый сервис публикует свою спецификацию, а Stoplight Hub аггрегирует их в единый портал:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| // Пример кода для экспорта OpenAPI из .NET сервиса
public static async Task ExportOpenApiToStoplight(string apiKey, string projectId)
{
var openApiJson = await GenerateOpenApiDocument();
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
var content = new StringContent(
openApiJson,
Encoding.UTF8,
"application/json");
var response = await client.PostAsync(
$"https://api.stoplight.io/v1/projects/{projectId}/versions",
content);
response.EnsureSuccessStatusCode();
} |
|
Возможности коллаборативной работы над API в Stoplight
Совместная работа над API — одна из самых больших головных болей во многих командах. В традиционном подходе разработчики обмениваются файлами спецификаций, сталкиваются с конфликтами слияния и тратят уйму времени на синхронизацию изменений. Stoplight кардинально меняет эту парадигму, предлагая мощные инструменты для коллаборации.
Прежде всего, Stoplight реализует концепцию совместного редактирования в реальном времени. Это почти как Google Docs для API-спецификаций — несколько человек могут одновременно работать над одним и тем же API, мгновенно видя изменения друг друга. Я наблюдал, как техлид и аналитик в режиме реального времени корректировали модели данных, обсуждая их по видеозвонку, и уже через час имели готовый контракт вместо нескольких дней итераций.
JavaScript | 1
2
3
4
5
6
7
8
9
| // Пример конфигурации для совместной работы в Stoplight
{
"collaboration": {
"enabled": true,
"realTimeEditing": true,
"commentingEnabled": true,
"suggestionMode": "track-changes"
}
} |
|
Система контроля доступа в Stoplight заслуживает особого упоминания. Вы можете назначать различные роли: администраторы, редакторы, рецензенты и зрители. Редакторы могут изменять спецификации, рецензенты — оставлять комментарии и утверждать изменения, а зрители имеют доступ только для чтения. Это критично в больших организациях, где над API работают разные команды с разными ответственостями.
Встроенная система комментариев и дискуссий — ещё одно золото для совместной работы. Любой участник может оставить комментарий к конкретному эндпоинту, параметру или схеме. Комментарии можно пометить как "вопрос", "предложение" или "проблема", что упрощает отслеживание и категоризация обратной связи. На одном проекте с распределённой командой (Москва, Санкт-Петербург, Новосибирск) мы внедрили Stoplight и забыли о проблемах версионности API-контрактов. Изменения вносились центральной командой, а другие подразделения видили изменения в реальном времени, что устранило сотни часов на синхронизацию.
В Stoplight встроен механизм пул-реквестов, что позволяет организовать процессы ревью и утверждения изменений, похожие на Git. Разработчик может создать ветку спецификации, внести изменения и отправить их на ревью. Ревьюеры оставляют комментарии, запрашивают правки или утверждают изменения, после чего они объединяются с основной версией спецификации.
Мониторинг и аналитика API через интеграции Stoplight
Мониторинг и аналитика API — та область, где Stoplight невероятно силён благодаря обширным возможностям интеграций. Не просто документировать API, но и понимать, как он используется, где возникают проблемы и какие эндпоинты наиболее востребованы — всё это критически важно для эволюции вашего интерфейса. Встроенные дашборды Stoplight предоставляют базовую статистику использования API — количество запросов, распределение по статус-кодам, время отклика. Но настояшая магия начинается при интеграции с внешними системами мониторинга:
JavaScript | 1
2
3
4
5
6
7
8
9
10
11
| // Конфигурация интеграции с Datadog
{
"integrations": {
"datadog": {
"enabled": true,
"apiKey": "YOUR_DATADOG_API_KEY",
"metrics": ["request_count", "latency", "error_rate"],
"tags": ["env:production", "service:payment-api"]
}
}
} |
|
Я помню проект финтех-платформы, где благодаря интеграции Stoplight с системой мониторинга мы выявили нетипичный паттерн использования платежного API. Оказалось, что один из партнеров "долбил" наш эндпоинт авторизации платежей вместо того, чтобы следовать документированному флоу с callback-уведомлениями. Без этой аналитики мы бы продолжали удивлятся странным скачкам нагрузки. Для углубленного анализа Stoplight позволяет настраивать бизнес-метрики и KPI, специфичные для вашего домена. Например, для платежного API можно отслеживать конверсию транзакций:
JSON | 1
2
3
4
5
6
7
8
9
10
| {
"metrics": {
"payment_conversion": {
"numerator": "successful_payments",
"denominator": "initiated_payments",
"threshold": 0.95,
"alert": true
}
}
} |
|
Особенно ценна возможность коррелировать изменения в спецификации API с изменениями в паттернах использования. После релиза новой версии API вы можете немедленно видеть, как это повлияло на поведение клиентов, какие новые эндпоинты стали популярными, а какие устаревшие продолжают использоватся вопреки рекомендациям.
Механизм аномалий в Stoplight автоматически детектирует необычные паттерны: резкие скачки трафика, увеличение количества ошибок или изменение соотношения между различными эндпоинтами. Это как иметь встроенного аналитика, который круглосуточно следит за здоровьем вашего API.
Сравнительный анализ альтернатив
Когда дело доходит до выбора замены для Swagger в проектах .NET, ситуация напоминает поиск идеальной пары обуви — универсального решения не существует, а выбор зависит от конкретных потребностей. Давайте взглянем на сильные и слабые стороны каждой альтернативы, которую мы рассмотрели.
NSwag, ReDoc и Stoplight — все они превосходят классический Swagger, но каждый инструмент имеет свой уникальный профиль. По производительности NSwag и ReDoc находятся примерно на одном уровне, но ReDoc лучше справляется с крупными спецификациями благодаря виртуализации отображения. Stoplight требует больше ресурсов, поскольку представляет собой полноценную платформу, а не просто инструмент для документации.
С точки зрения сложности внедрения картина меняется. NSwag прекрасно интегрируется с ASP.NET Core и требует минимум усилий для старта. ReDoc можно подключить буквально за 10 минут, а вот Stoplight потребует организационных изменений и обучения команды.
C# | 1
2
3
4
5
6
7
8
9
| // Сравнительная оценка по 5-балльной шкале
| NSwag | ReDoc | Stoplight
----------------------|-------|-------|----------
Простота внедрения | 4 | 5 | 2
Документирование | 4 | 5 | 5
Генерация клиентов | 5 | 1 | 4
Коллаборация | 2 | 1 | 5
Визуальный дизайн | 3 | 4 | 5
Интеграция с CI/CD | 4 | 3 | 5 |
|
Что касается сценариев применения, у меня сложилась определённая картина после работы со всеми тремя инструментами. NSwag идеален для команд .NET-разработчиков, которые хотят получить простое решение "из коробки" с максимальной интеграцией. Это оружие выбора для проектов, где важна автоматическая генерация клиентского кода.
ReDoc сияет там, где критична читабельность документации и её визуальное оформление. Я видел, как бизнес-клиенты буквально аплодировали, когда мы переходили от стандартного Swagger UI к элегантной документации на ReDoc. Если основная цель — создать понятную, эстетичную документацию для вашего API, ReDoc — лучший выбор.
Stoplight же занимает особую нишу. Это выбор для организаций, серьёзно относящихся к дизайну API как к стратегическому активу. В крупной компании с десятками микросервисов и несколькими командами разработки Stoplight может оказаться спасением, превращая хаос в структурированую API-экосистему.
Особенности миграции с Swagger на альтернативные решения
Переход с Swagger на новые решения – процесс, который требует стратегического подхода. Если вы решились на миграцию, помните старую мудрость программистов: "работающее не трогай". Поэтапный переход почти всегда лучше резкой замены. Когда мы переходили с Swagger на ReDoc в финтех-проекте, первым шагом был параллельный запуск обоих решений. Это дало возможность командам постепенно привыкнуть к новому интерфейсу без потери продуктивности:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // Параллельный запуск Swagger и ReDoc
if (app.Environment.IsDevelopment())
{
// Старый Swagger UI
app.UseSwagger();
app.UseSwaggerUI();
// Новый ReDoc, размещенный на другом маршруте
app.UseReDoc(options =>
{
options.SpecUrl = "/swagger/v1/swagger.json"; // Используем тот же JSON
options.RoutePrefix = "api-docs";
});
} |
|
Удивительно, но большинство проблем при миграции связаны не с техническими аспектами, а с человеческим фактором. Разработчики, привыкшие к Swagger UI, сначала сопротивляются переменам. Решение? Документируйте преимущества нового подхода и проводите демонстрации для команды.
Для сложных API с кастомными расширениями Swagger будьте готовы провести аудит спецификации. Некоторые вендор-специфические расширения могут не поддерживаться новыми инструментами. Мы столкнулись с этим при использовании специфичных для Swagger атрибутов [SwaggerSubType] . В NSwag пришлось искать аналоги:
C# | 1
2
3
4
5
6
7
8
9
10
| // Было в Swagger
[SwaggerSubType(typeof(CreditCardPayment))]
[SwaggerSubType(typeof(PayPalPayment))]
public abstract class PaymentMethod { /* ... */ }
// Стало в NSwag
[JsonConverter(typeof(JsonInheritanceConverter), "discriminator")]
[KnownType(typeof(CreditCardPayment))]
[KnownType(typeof(PayPalPayment))]
public abstract class PaymentMethod { /* ... */ } |
|
Особое внимание при миграции уделите CI/CD пайплайнам. Замена инструмента документации часто требует обновления скриптов сборки и развертывания, особенно если вы генерируете клиентские SDK.
Различия между .NET Framework 1.0 и .NET Framework 1.1 Я недавно себе установил .NET Framework 1.1, а различие между .NET Framework 1.0 не нашел. Нет... Что лучше выбрать VB.NET или C.NET (C#)? Я программирую на VB. Но так как сейчас появилась .NET платформа решил перейти на неё.
Подскажите... Как указать VS.NET какой из установленный .NET Framewrok SDK использовать У меня есть дистрибутив VS.NET2002. При инсталляции он ставит .NET Framewrok SDK v1.0.3705
Я... Как установить .NET приложение, но без установки самого .NET Framework? Мне нужно установить .NET приложение, но без установки самого .NET Framework. Возможно ли это? есть... Какие отличия .NET и .NET 2003? Доброго времени суток.
В инете надыбали .NET 2003, в связи с чем и вопрос - кто нить работал с... Client ASP.NET MVC + Angular и Server side ASP.NET WEB.API Доброго времени суток!
Не первый день бьюсь над задачей, не могу понять в чем причина.
Хочу... ASP.NET .NET Core Web Api -- почему параметры всегда null? Что я делаю не так?
using Microsoft.AspNetCore.Mvc;
namespace WebApiServer.Controllers
{
... Разница между .Net Framework и .Net Core Собственно, основной вопрос в названии темы.
Из прочитанных статей понял, что core призван... Библиотека NETSquirrel для .NET и .NET Core Краткое описание
NETSquirrel - идейное продолжение и обобщение системного модуля PABCSystem на... На какой платформе лучше создавать бота? .NET Framework или .NET Core? Здравствуйте знатоки, постараюсь расписать вопрос максимально подробно..
Пытаюсь разработать Бота... Чем хорош C++.NET по сравнению с VC++ 6.0? Вопрос в следующем:
есть вариант перейти на среду разработки NET,
чем она лучше и не будет ли... Как лучше группировать объекты? Просто чем VB.NET лучше? Я недавно установил VB.NET и столкнулся с такой проблемой:
раньше, в VB6 я клал чекбоксы, бутоны...
|