Рубрики
Программирование

Прощай Swagger, привет Scalar

Swagger — это не зависящая от языка спецификация для описания REST API. Она позволяет компьютерам и пользователям лучше понять возможности REST API без прямого доступа к исходному коду. Точнее позволяла, ведь Microsoft удаляет встроенную поддержку Swagger (Swashbuckle) в .NET 9 из-за проблем с обслуживанием и перехода на встроенную поддержку OpenAPI. Вместо этого в качестве альтернативного инструмента для документации API предлагается Scalar с простой интеграцией и настраиваемыми функциями, включая схемы аутентификации.

Почему удален Swagger?

Команда разработчиков ASP.NET Core решила удалить встроенную поддержку Swagger (Swashbuckle) из .NET 9 по нескольким причинам:

  1. Проблемы с поддержкой: проект Swashbuckle больше не поддерживается его владельцем. Проблемы не устраняются и не решаются, и не было официального выпуска для .NET 8.
  2. Эволюция ASP.NET Core: с момента появления поддержки Swagger в .NET 5 ASP.NET Core значительно изменился. Теперь он включает встроенную поддержку метаданных, необходимых для описания веб-API, что снижает потребность во внешних инструментах.
  3. Сосредоточенность на OpenAPI: команда стремится сделать OpenAPI более интегрированной функцией в ASP.NET Core. Они планируют расширить возможности Microsoft.AspNetCore.OpenApi для создания документов OpenAPI без использования внешних пакетов.
  4. Альтернативные инструменты: теперь Visual Studio предлагает встроенную поддержку для файлов .http и новый инструмент Endpoints Explorer, предоставляющий альтернативные способы изучения, тестирования и отладки API.
  5. Инновации, ориентированные на сообщество: удаляя зависимость по умолчанию, команда поощряет использование и разработку различных инструментов OpenAPI, которые могут лучше соответствовать конкретным потребностям проекта.

Новый альтернативный инструмент — Scalar

Scalar — это интерактивный инструмент для создания документации API, который работает с документами OpenAPI/Swagger. Вы можете получить более подробную информацию здесь, а если потребуется посмотреть код, то можно глянуть сюда.

Давайте попробуем добавить Scalar в свежесозданный проект из шаблона. Для начала необходимо установить Nuget-пакет:

dotnet add package Scalar.AspNetCore

И добавим соответствующее пространство имён:

using Scalar.AspNetCore;

Добавьте следующее в Program.cs на основе вашего генератора OpenAPI. Для .Net 9 нужно использовать Microsoft.AspNetCore.OpenApi:

builder.Services.AddOpenApi();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.MapScalarApiReference();
}

Для .Net 8 есть два варианта. Первый это использовать Swashbuckle:

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger(options =>
    {
        options.RouteTemplate = "/openapi/{documentName}.json";
    });
    app.MapScalarApiReference();
}

Альтернативный вариант использоваться NSwag:

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApiDocument();

if (app.Environment.IsDevelopment())
{
    app.UseOpenApi(options =>
    {
        options.Path = "/openapi/{documentName}.json";
    });
    app.MapScalarApiReference();
}

В целом готово. Для простейшего сценария использования этого будет достаточно — в большинстве случаев настроек по умолчанию хватит, а страницу с информацией мы увидим по адресу /scalar/v1, где v1 имя файла по умолчанию.

Пример кода

Давайте посмотрим на то как выглядит это на примере. Добавим к стандартному решению ещё один эндпоинт app.MapGet("/", () => "Hello world!"), чтобы их у нас было больше одного. В результате мы получим вот такой код:

using Scalar.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.MapScalarApiReference();
    app.MapOpenApi();
}

app.UseHttpsRedirection();

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/", () => "Hello world!");

app.MapGet("/weatherforecast", () =>
    {
        var forecast = Enumerable.Range(1, 5).Select(index =>
                new WeatherForecast
                (
                    DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                    Random.Shared.Next(-20, 55),
                    summaries[Random.Shared.Next(summaries.Length)]
                ))
            .ToArray();
        return forecast;
    })
    .WithName("GetWeatherForecast");

app.Run();

record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

Посмотрим на результат по адресу http(s)://localhost:{port}/scalar/v1:

Рис. 1 Скрин с добавленным методом
Рис. 2 Скрин с методом по умолчанию

Настройка конфигурации


Метод MapScalarApiReference принимает необязательный параметр options, который можно использовать для настройки Scalar с помощью Fluent API или синтаксиса инициализации объектов:

app.MapScalarApiReference(options =>
{
    // Fluent API
    options
        .WithTitle("Custom API")
        .WithSidebar(false);

    // Инициализация объекта
    options.Title = "Custom API";
    options.ShowSidebar = false;
});

Разумеется, использовать его не обязательно (на то это и необязательный параметр :) ) и настроек по умолчанию хватит для нормальной работы, но если хочется навести красоту, то почему бы и нет?

Настройка авторизации

В целом всё что нужно для pet-project уже посмотрели. Но что если мы хотим потыкать что-то с аутентификацией? В таком случае нам может потребоваться добавить один из вариантов аутентификации — включая API-ключ, OAuth, HTTP Basic и Bearer, позволяя предварительно заполнять некоторые данные для аутентификации.

Ключ API

Чтобы упростить использование ключа API, вы можете предоставить токен:

app.MapScalarApiReference(options =>
{
    // Fluent API
    options
        .WithPreferredScheme("ApiKey") // Имя схемы безопасности из документа OpenAPI
        .WithApiKeyAuthentication(apiKey =>
        {
            apiKey.Token = "your_api_key";
        });

    // Инициализация объекта
    options.Authentication = new ScalarAuthenticationOptions
    {
        PreferredSecurityScheme = "ApiKey", // Имя схемы безопасности из документа OpenAPI
        ApiKey = new ApiKeyOptions
        {
            Token = "your_api_key"
        }
    }
});

OAuth

Аналогичным образом вы можете предварительно заполнить поля OAuth, такие как идентификатор клиента и области действия:

app.MapScalarApiReference(options =>
{
    options
        .WithPreferredScheme("OAuth2") // Имя схемы безопасности из документа OpenAPI
        .WithOAuth2Authentication(oauth =>
        {
            oauth.ClientId = "your_client_id";
            oauth.Scopes = ["profile"];
        });
});

HTTP Basic/Bearer

Поля аутентификации HTTP Basic или с использованием Bearer-токена также можно легко заполнить заранее:

app.MapScalarApiReference(options =>
{
    // HTTP Basic
    options
        .WithPreferredScheme("Basic") // Имя схемы безопасности из документа OpenAPI
        .WithHttpBasicAuthentication(basic =>
        {
            basic.Username = "your_username";
            basic.Password = "your_password";
        });

    // Bearer
    options
        .WithPreferredScheme("Bearer") // Имя схемы безопасности из документа OpenAPI
        .WithHttpBearerAuthentication(bearer =>
        {
            bearer.Token = "your_bearer_token";
        });
});

Использование OpenAPI документа

Для тех, кто придерживается Design API First подхода в разработке также есть возможность использовать OpenAPI документ. Scalar ожидает, что он будет находиться по адресу /openapi/{documentName}.json, соответствующему маршруту встроенного генератора .NET OpenAPI в пакете Microsoft.AspNetCore.OpenApi. Если документ находится в другом месте, укажите путь с помощью свойства OpenApiRoutePattern:

app.MapScalarApiReference(options =>
{
    options.WithOpenApiRoutePattern("/{document_path}/{documentName}.json");
    // или
    options.OpenApiRoutePattern = "/{document_path}/{documentName}.json";
});

Заключение

Не смотря на то, что Swagger сослужил нам хорошую службу пришло время с ним прощаться. Ему на смену пришёл Scalar, который также позволяет создавать, документировать и проверять API. И теперь вы готовы к его использованию :)