Published on
🍵 4 min read

An Alternative to Swagger in .NET 9: Scalar

Authors

Photo

Overview

TL;DR

Microsoft is removing built-in Swagger support (Swashbuckle) in .NET 9 due to maintenance issues and a shift towards integrated OpenAPI support. Instead, Scalar is suggested as an alternative tool for API documentation, with easy integration and customizable features, including authentication schemes.

Introduction

Microsoft has decided to remove built-in Swagger support (Swashbuckle) from .NET 9.

Why is Swagger (Swashbuckle) Being Removed?

The ASP.NET Core team has decided to remove built-in Swagger support (Swashbuckle) from .NET 9 for several reasons:

  1. Maintenance Issues: The Swashbuckle project is no longer actively maintained by its community owner. Issues are not being addressed or resolved, and there hasn't been an official release for .NET 8.
  2. Evolution of ASP.NET Core: Since Swagger support was introduced in .NET 5, ASP.NET Core has evolved significantly. It now includes built-in support for the metadata necessary to describe a web API, reducing the need for external tools.
  3. Focus on OpenAPI: The team aims to make OpenAPI a more integrated feature in ASP.NET Core. They plan to expand the capabilities of Microsoft.AspNetCore.OpenApi to provide OpenAPI document generation without relying on external packages.
  4. Alternative Tools: Visual Studio now offers built-in support for .http files and the new Endpoints Explorer, providing alternative ways to explore, test, and debug APIs.
  5. Community-Driven Innovation: By removing the default dependency, the team encourages the use and development of various OpenAPI tools that might better suit specific project needs.

An Alternative to Swagger: Scalar

Scalar is an interactive API documentation tool that works with OpenAPI/Swagger documents.

You can get more information here.

How to Use Scalar in .NET 9

1 - Installation

dotnet add package Scalar.AspNetCore

2 - Example Usage

using Scalar.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();

var app = builder.Build();

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

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

app.Run();

When you run the application, you can access the API documentation at the scalar/v1 endpoint.

Here are the example screenshots from API documentation:

scalar-1 scalar-2 scalar-3 scalar-4

How to Add a Bearer Authentication Scheme to Scalar

Here is an example transformer for Bearer authentication:

public sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
{
    public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
    {
        var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
        if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
        {
            // Add the security scheme at the document level
            var requirements = new Dictionary<string, OpenApiSecurityScheme>
            {
                ["Bearer"] = new OpenApiSecurityScheme
                {
                    Type = SecuritySchemeType.Http,
                    Scheme = "bearer", // "bearer" refers to the header name here
                    In = ParameterLocation.Header,
                    BearerFormat = "JWT"
                }
            };
            document.Components ??= new OpenApiComponents();
            document.Components.SecuritySchemes = requirements;

            // Apply it as a requirement for all operations
            foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations))
            {
                operation.Value.Security.Add(new OpenApiSecurityRequirement
                {
                    [new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Id = "Bearer",
                            Type = ReferenceType.SecurityScheme
                        }
                    }] = Array.Empty<string>()
                });
            }
        }
    }
}

Example Usage

builder.Services.AddOpenApi(opt =>
{
    opt.UseTransformer<BearerSecuritySchemeTransformer>();
});

Frequently Asked Questions