Содержание
До сих пор мы разрабатывали нашы проекты ASP.NET Core Web API, особенно не вдаваясь в вопросы документирования тех или иных возможностей и функций приложения. Между тем, документирование API – это, едва ли не самая важная часть работы над проектом, если вы планируете его распространять среди широкого круга пользователей. Именно документация API позволяет потенциальным и уже имеющимся пользователям разобраться с тем, как работает ваш API, какие методы предоставляет, как его эффективно использовать и так далее.
Что такое Swagger и OpenAPI?
OpenAPI — это не зависящая от языка спецификация для описания REST API. В 2015 году OpenAPI Initiative был передан проект под названием Swagger – инструментарий для описания API с использованием спецификации OpenAPI. На сегодняшний день эти два названия – OpenAPI и Swagger стали на столько тесно связанными, что их можно даже назвать взаимозаменяемыми. Даже в разделе официального сайта Microsoft, посвященному работе со Swagger первое же предложение начинается со слов «Swagger (OpenAPI) – это спецификация…», хотя, если быть предельно строгими к описанию, то спецификацией является OpenAPI, а Swagger – всего лишь инструмент для работы в соответствии с этой спецификацией, хотя и довольно мощный, и удобный.
Nuget-пакеты для Swagger
В ASP.NET Core существует две реализации OpenAPI – это Swashbuckle и NSwag. Причем, по умолчанию, при создании проекта ASP.NET Core Web API используется именно первая реализация.
Swagger в ASP.NET Core использует три компонента:
- AspNetCore.Swagger – содержит объектную модель Swagger и промежуточное программное обеспечение для предоставления объектов SwaggerDocument в формате JSON.
- AspNetCore.SwaggerGen – генератор Swagger, который создает объекты SwaggerDocument непосредственно из наших маршрутов, контроллеров и моделей.
- AspNetCore.SwaggerUI – встроенная версия инструмента пользовательского интерфейса Swagger. Он интерпретирует Swagger JSON для создания богатых и настраиваемых возможностей описания функций веб-API.
Для того, чтобы воспользоваться всеми этими компонентами, нам необходимо установить nuget-пакет Swashbuckle.AspNetCore. После установки пакета в «Обозревателе решений» Visual Studio проект будет выглядеть следующим образом
Настройка Swagger в приложении
Настроим работу Swagger в нашем приложении. Для этого перейдем в файл Program.cs и внесем в него следующие изменения
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddSwaggerGen(); var app = builder.Build(); app.UseHttpsRedirection(); app.UseSwagger(); app.UseSwaggerUI(); app.UseAuthorization(); app.MapControllers(); app.Run();
Здесь мы подключаем необходимый сервис для генерации документов Swagger
builder.Services.AddSwaggerGen();
и встраиваем два компонента middleware в конвейер обработки запросов.
app.UseSwagger(); app.UseSwaggerUI();
При этом мы оставляем все настройки Swagger со значениями по умолчанию. Теперь запустим приложение, откроем любой браузер и перейдем по адресу https://localhost:[port]/swagger/. В результате вы увидите Swagger UI, где в удобном виде будут сгруппированы все методы API, которые мы добавляли в наше приложение
Методы API сгруппированы по контроллерам. Также, в этом же окне представлены и все схемы данных, которые используются в приложении
Конечные точки Swagger
На данный момент пользовательский интерфейс Swagger доступен по адресу https://localhost:[port]/swagger/, а если вы перейдете по адресу https://localhost:[port]/swagger/v1/swagger.json, то увидите сформированный документ Swagger (см. рис):
Этот документ содержит описание всех методов API, созданное с использованием спецификации OpenAPI 3.0.1. При необходимости мы можем менять как расположение документа Swagger, так и адрес расположения пользовательского интерфейса. Например
app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1"); options.RoutePrefix = string.Empty; });
Здесь в методе расширения UseSwaggerUI()
мы добавили настройки – конечную точку расположения документа Swagger
options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
А также указали для свойства RoutePrefix
пустую строку, которая означает, что пользовательский интерфейс Swagger будет доступен по адресу https://localhost:[port].
Общие сведения об API
Также мы можем добавить общие сведения об API, используя настройки сервиса Swagger
builder.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo() { Description = "Web API на основе контроллеров", Title = "Web API v1", Version = "v1", Contact = new Microsoft.OpenApi.Models.OpenApiContact() { Email = "admin@webdelphi.ru", Name = "Vlad", Url = new Uri("https://csharp.webdelphi.ru") } }); });
Здесь мы добавили версия API, небольшое описание и контактные данные. В интерфейсе Swagger эта информация будет выглядеть следующим образом
Настройка авторизации
Для того, чтобы использовать механизмы авторизации при тестировании запросов к API в Swagger необходимые настройки авторизации также добавляются при регистрации сервиса в контейнере зависимостей. Например, добавим авторизацию с использованием JWT-токенов, которую мы создавали ранее для нашего приложения
builder.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo() { Description = "Web API на основе контроллеров", Title = "Web API v1", Version = "v1", Contact = new Microsoft.OpenApi.Models.OpenApiContact() { Email = "admin@webdelphi.ru", Name = "Vlad", Url = new Uri("https://csharp.webdelphi.ru") } }); //настройки авторизации options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() { Description = "Скопируйте сюда ключ доступа и добавьте в начале строку \"Bearer\"", In = ParameterLocation.Header, Scheme = "Bearer", Type = SecuritySchemeType.ApiKey, Name = "Authorization" }); options.AddSecurityRequirement(new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "Bearer" }, Name = "Bearer", }, new List<string>() } }); });
Здесь мы определяем способ авторизации
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() { Description = "Скопируйте сюда ключ доступа и добавьте в начале строку \"Bearer\"", In = ParameterLocation.Header, Scheme = "Bearer", Type = SecuritySchemeType.ApiKey, Name = "Authorization" });
указав место расположения ключа доступа (ParameterLocation.Header
– заголовок), имя схемы авторизации, которое должно использоваться в заголовке («Bearer»), тип схемы безопасности (SecuritySchemeType.ApiKey
), имя заголовка в котором будет размещаться ключ безопасности («Authorization»), а также подсказку для клиента API. И далее мы добавили объект, определяющий требования безопасности.
options.AddSecurityRequirement(new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "Bearer" }, Name = "Bearer", }, new List<string>() } });
Здесь имя объекта полностью соответствует имени схемы, которое мы определили выше при описании способа авторизации. Теперь, если запустить приложение и открыть в браузере Swagger UI, то мы должны увидеть следующее изменение в интерфейсе
Для того, чтобы авторизоваться в Swagger UI для выполнения запросов к API, необходимо нажать кнопку Authorize и ввести ключ доступа:
После этого можно выбрать в списке какой-либо метод API, требующий авторизации и выполнить его.
Добавление описания методов API
Swagger – это не столько инструмент для тестирования методов API, сколько инструмент для документирования API. Однако, на данный момент, из всей документации по API у нас только его краткое описание. Исправим этот момент, позволив Swagger создавать документацию по API, используя XML-комментарии в коде. Для этого перейдем в свойства проекта в Visual Studio, кликнув правой кнопкой мыши по его названию в обозревателе решений
В разделе «Сборка —> Выходные данные» необходимо установить флажок напротив пункта «Файл документации» и указать имя XML-файла в котором будет храниться документация по API
Теперь нам необходимо настроить Swagger на использование этого файла. Сделать это можно так же, как и настройку авторизации – при добавлении сервиса
builder.Services.AddSwaggerGen(options => { //добавление общих сведений о приложении //тут код настройки общих сведений //настройки авторизации //тут код настройки авторизации //настраиваем Swagger на чтение XML-комментариев var xmlPath = Path.Combine(Environment.CurrentDirectory, "documentation.xml"); options.IncludeXmlComments(xmlPath); });
Чтобы не повторять уже рассмотренный выше код настройки сервиса, здесь показаны только новые строки кода, в которых мы указываем для Swagger путь к файлу с XML-комментариями.
Теперь перейдем к какому-нибудь контроллеру API и создадим документацию. Например, откроем файл WeatherForecastController
, поставим курсор мыши над методом Get()
и трижды нажмем на клавиатуре «/» (слэш). В результате сгенерируется стандартный шаблон описания метода
/// <summary> /// /// </summary> /// <returns></returns> [HttpGet] public IEnumerable<WeatherForecast> Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); }
Добавим описание метода.
/// <summary> /// Возвращает прогноз погоды на пять дней /// </summary> /// <returns>Список обхектов WeatherForecast</returns> [HttpGet] public IEnumerable<WeatherForecast> Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); }
Теперь запустим приложение и откроем в браузере Swagger UI
Похожим образом мы можем добавлять описания для параметров методов, если они используются в действии контроллера.
Также при описании Web API важно предоставлять информацию не только о параметрах методов и их назначении, но и о том, какие коды статуса HTTP может возвращать тот или иной метод и что эти коды означают для пользователя. Чтобы добавить описание возвращаемых кодов статуса для метода используется специальный атрибут [ProducesResponseType]
, а в XML-комментарии <response code=”код_статуса”>
, например
/// <summary> /// Возвращает прогноз погоды на пять дней /// </summary> /// <returns>Список обхектов WeatherForecast</returns> /// <response code="200">Запрос на добавление новой роли успешно выполнен</response> /// <response code="400">Ошибка выполнения запроса</response> [HttpGet] [ProducesResponseType(typeof(IdentityResult), 200, "application/json")] [ProducesResponseType(typeof(ProblemDetails), 400, "application/json")] public IEnumerable<WeatherForecast> Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); }
Здесь мы использовали атрибут ProducesResponseType
с тремя параметрами – тип возвращаемого результата, код статуса HTTP, тип данных в теле ответа. Обязательным из этих параметров является только код статуса. Теперь запустим приложение и посмотрим на описание кодов статуса для метода в Swagger UI
Аналогичным образом, используя XML-комментарии, мы можем добавлять описание для свойств моделей, используемых в API, а также использовать аннотации данных для указания обязательных полей (свойств) модели.
Тестирование API в Swagger UI
С помощью Swagger UI мы можем тестировать запросы к API. Для этого необходимо раскрыть вкладку с необходимым методом, например, как показано на рисунке выше, а затем последовательно нажать кнопки «Try It Out» и «Execute». Если же метод API подразумевает отправку каких-либо данных или использование параметров запроса, то их также необходимо предварительно заполнить в соответствующих полях. Ниже представлен результат выполнения метода Get()
контроллера WeatherForecastController
.
Итого
Для документирования API в ASP.NET Core мы можем использовать инструмент Swagger, который умеет работать с документацией в коде приложения. При необходимости, мы можем настроить Swagger UI для работы с методами, для которых требуется авторизация, например, с использованием JWT-токенов.