Introdução ao NSwag e ao ASP.NET Core

Por Christoph Nienaber, Rico Suter e Dave Brock

Exibir ou baixar código de exemplo (como baixar)

NSwag oferece os seguintes recursos:

  • A capacidade de utilizar a interface do usuário do Swagger e o gerador do Swagger.
  • Recursos flexíveis de geração de código.

Com o NSwag, você não precisa de uma API existente, pois pode usar APIs de terceiros que incorporam o Swagger e geram uma implementação de cliente. O NSwag permite acelerar o ciclo de desenvolvimento e adaptar-se facilmente às alterações na API.

Instalação do pacote

Instale o NSwag para:

  • Gerar a especificação do Swagger para a API Web implementada.
  • Oferecer a interface do usuário do Swagger para navegar e testar a API Web.
  • Oferecer o Redoc para adicionar a documentação da API para a API Web.

Para usar o middleware ASP.NET Core do NSwag, instale o pacote do NuGet NSwag.AspNetCore. Este pacote contém o middleware para gerar e oferecer a especificação do Swagger, interface do usuário do Swagger (v2 e v3) e a interface do usuário do ReDoc. O NSwag 14 dá suporte apenas à v3 da especificação de interface do usuário do Swagger.

Use uma das seguintes abordagens para instalar o pacote do NuGet do NSwag:

  • Da janela Console do Gerenciador de Pacotes:

    • Acesse Exibição>Outras Janelas>Console do Gerenciador de Pacotes

    • Navegue para o diretório no qual o arquivo NSwagSample.csproj está localizado

    • Execute o comando a seguir:

      Install-Package NSwag.AspNetCore
      
  • Da caixa de diálogo Gerenciar Pacotes NuGet:

    • Clique com o botão direito do mouse no projeto em Gerenciador de Soluções>Gerenciar Pacotes NuGet
    • Defina a Origem do pacote para "nuget.org"
    • Insira "NSwag.AspNetCore" na caixa de pesquisa
    • Selecione o pacote "NSwag.AspNetCore" na guia Procurar e clique em Instalar

Adicionar e configurar o middleware do Swagger

Realize estas etapas para adicionar e configurar o Swagger em seu aplicativo ASP.NET Core:

  • Adicione o gerador do OpenApi à coleção de serviços no Program.cs:
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddOpenApiDocument();
  • Habilite o middleware para atender à especificação do OpenApi gerado, à interface do usuário do Swagger UI e a interface do usuário do Redoc, também no Program.cs:
if (app.Environment.IsDevelopment())
{
    // Add OpenAPI 3.0 document serving middleware
    // Available at: http://localhost:<port>/swagger/v1/swagger.json
    app.UseOpenApi();

    // Add web UIs to interact with the document
    // Available at: http://localhost:<port>/swagger
    app.UseSwaggerUi(); // UseSwaggerUI Protected by if (env.IsDevelopment())
}
  • Inicie o aplicativo. Navegue até:
    • http://localhost:<port>/swagger para exibir a interface do usuário do Swagger.
    • http://localhost:<port>/swagger/v1/swagger.json para exibir a especificação do Swagger.

Geração de código

Você pode tirar proveito dos recursos de geração de código do NSwag, escolhendo uma das opções a seguir:

Gerar o código com NSwagStudio

  • Instale o NSwagStudio, seguindo as instruções no repositório GitHub do NSwagStudio. Na página de versão do NSwag, você pode fazer o download de uma versão xcopy que pode ser iniciada sem privilégios de instalação e administrador.
  • Inicie o NSwagStudio e insira a URL do arquivo swagger.json na caixa de texto URL de Especificação do Swagger. Por exemplo, http://localhost:5232/swagger/v1/swagger.json.
  • Clique no botão Criar Cópia local para gerar uma representação JSON de sua especificação do Swagger.

O NSwag Studio importa a especificação e exporta um cliente CSharp.

  • Na área Saídas, marque a caixa de seleção Cliente CSharp. Dependendo do seu projeto, você também pode escolher Cliente TypeScript ou Controlador da API Web CSharp. Se você selecionar Controlador da API Web do CSharp, uma especificação de serviço recompilará o serviço, que servirá como uma geração inversa.
  • Clique em Gerar Saídas para produzir uma implementação completa de cliente em C# do projeto TodoApi.NSwag. Para ver o código de cliente gerado, clique na guia Cliente do CSharp:
namespace MyNamespace
{
    using System = global::System;

    [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.1.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")]
    public partial class TodoClient
    {
    #pragma warning disable 8618 // Set by constructor via BaseUrl property
        private string _baseUrl;
    #pragma warning restore 8618 // Set by constructor via BaseUrl property
        private System.Net.Http.HttpClient _httpClient;
        private static System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings, true);

        public TodoClient(System.Net.Http.HttpClient httpClient)
        {
            BaseUrl = "http://localhost:5232";
            _httpClient = httpClient;
        }

        private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()
        {
            var settings = new Newtonsoft.Json.JsonSerializerSettings();
            UpdateJsonSerializerSettings(settings);
            return settings;
        }

        public string BaseUrl
        {
            get { return _baseUrl; }
            set
            {
                _baseUrl = value;
                if (!string.IsNullOrEmpty(_baseUrl) && !_baseUrl.EndsWith("/"))
                    _baseUrl += '/';
            }
        }
        // code omitted for brevity

Dica

O código do cliente C# é gerado com base em seleções na guia Configurações. Modifique as configurações para executar tarefas como renomenclatura de namespace padrão e geração de método síncrono.

  • Copie o código C# gerado em um arquivo no projeto do cliente que consumirá a API.
  • Inicie o consumo da API Web:
var todoClient = new TodoClient(new HttpClient());

// Gets all to-dos from the API
var allTodos = await todoClient.GetAsync();

// Create a new TodoItem, and save it via the API.
await todoClient.CreateAsync(new TodoItem());

// Get a single to-do by ID
var foundTodo = await todoClient.GetByIdAsync(1);

Personalizar a documentação da API

O OpenApi fornece opções para documentar o modelo de objeto para facilitar o consumo da API Web.

Descrição e informações da API

Em Program.cs, atualize AddOpenApiDocument para configurar as informações do documento da API Web e incluir mais informações, como o autor, a licença e a descrição. Primeiro importe o namespace NSwag para usar as classes OpenApi.

using NSwag;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApiDocument(options => {
     options.PostProcess = document =>
     {
         document.Info = new OpenApiInfo
         {
             Version = "v1",
             Title = "ToDo API",
             Description = "An ASP.NET Core Web API for managing ToDo items",
             TermsOfService = "https://example.com/terms",
             Contact = new OpenApiContact
             {
                 Name = "Example Contact",
                 Url = "https://example.com/contact"
             },
             License = new OpenApiLicense
             {
                 Name = "Example License",
                 Url = "https://example.com/license"
             }
         };
     };
});

A interface do usuário do Swagger exibe as informações da versão:

Interface do usuário do Swagger com informações de versão.

comentários XML

Para habilitar os comentários XML, execute as seguintes etapas:

  • Clique com o botão direito do mouse no projeto em Gerenciador de Soluções e selecione Edit <project_name>.csproj.
  • Adicione manualmente as linhas realçadas ao arquivo .csproj:
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

A habilitação de comentários XML fornece informações de depuração para os membros e os tipos públicos não documentados. Os membros e tipos não documentados são indicados por mensagem de aviso. Por exemplo, a seguinte mensagem indica uma violação do código de aviso 1591:

warning CS1591: Missing XML comment for publicly visible type or member 'TodoContext'

Para suprimir os avisos de todo o projeto, defina uma lista separada por ponto e vírgula dos códigos de aviso a serem ignorados no arquivo do projeto. Acrescentar os códigos de aviso ao $(NoWarn); também aplica os valores padrão C#.

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

Para suprimir avisos somente para membros específicos, coloque o código nas diretivas de pré-processador #pragma warning. Essa abordagem é útil para código que não deve ser exposto por meio dos documentos da API. No exemplo a seguir, o código de aviso CS1591 é ignorado para toda a classe TodoContext. A imposição do código de aviso é restaurada no fechamento da definição de classe. Especifique vários códigos de aviso com uma lista delimitada por vírgulas.

namespace NSwagSample.Models;

#pragma warning disable CS1591
public class TodoContext : DbContext
{
    public TodoContext(DbContextOptions<TodoContext> options) : base(options) { }

    public DbSet<TodoItem> TodoItems => Set<TodoItem>();
}
#pragma warning restore CS1591

Anotações de dados

Marque o modelo com atributos encontrados no namespace de System.ComponentModel.DataAnnotations para ajudar a controlar os componentes de interface do usuário do Swagger.

Adicione o atributo [Required] à propriedade Name da classe TodoItem:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace NSwagSample.Models;

public class TodoItem
{
    public long Id { get; set; }

    [Required]
    public string Name { get; set; } = null!;

    [DefaultValue(false)]
    public bool IsComplete { get; set; }
}

A presença desse atributo altera o comportamento da interface do usuário e altera o esquema JSON subjacente:

"TodoItem": {
  "type": "object",
  "additionalProperties": false,
  "required": [
    "name"
  ],
  "properties": {
    "id": {
      "type": "integer",
      "format": "int64"
    },
    "name": {
      "type": "string",
      "minLength": 1
    },
    "isComplete": {
      "type": "boolean",
      "default": false
    }
  }
}

À medida que aumenta o uso de anotações de dados na API Web, a interface do usuário e as páginas de ajuda da API se tornam mais descritivas e úteis.

Descrever os tipos de resposta

Os desenvolvedores que usam uma API Web estão mais preocupados com o que é retornado — mais especificamente, os tipos de resposta e os códigos de erro (se eles não forem padrão). Os tipos de resposta e os códigos de erro são indicados nos comentários XML e nas anotações de dados.

A ação Create retorna um código de status HTTP 201 em caso de sucesso. Um código de status HTTP 400 é retornado quando o corpo da solicitação postada é null. Sem a documentação adequada na interface do usuário do Swagger, o consumidor não tem conhecimento desses resultados esperados. Corrija esse problema adicionando as linhas realçadas no exemplo a seguir:

/// <summary>
/// Creates a TodoItem.
/// </summary>
/// <param name="item"></param>
/// <returns>A newly created TodoItem</returns>
/// <remarks>
/// Sample request:
///
///     POST /Todo
///     {
///        "id": 1,
///        "name": "Item #1",
///        "isComplete": true
///     }
///
/// </remarks>
/// <response code="201">Returns the newly created item</response>
/// <response code="400">If the item is null</response>
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Create(TodoItem item)
{
    _context.TodoItems.Add(item);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(Get), new { id = item.Id }, item);
}

A interface do usuário do Swagger agora documenta claramente os códigos de resposta HTTP esperados (e os comentários XML também são exibidos):

A interface do usuário do Swagger mostra a descrição da classe de resposta POST, 'Retorna o item de tarefa pendente recém-criado' e '400 – se o item for nulo' para o código de status e o motivo em Mensagens de Resposta.

As convenções podem ser usadas como uma alternativa para decorar explicitamente as ações individuais com [ProducesResponseType]. Para obter mais informações, confira Usar convenções da API Web.

Redoc

O Redoc é uma alternativa à interface do usuário do Swagger. É semelhante porque também disponibiliza uma página de documentação para a API Web usando a especificação OpenAPI. A diferença é que a interface do usuário do Redoc está mais focada na documentação e não fornece uma interface do usuário interativa para testar a API.

Para habilitar o Redoc, adicione seu middleware no Program.cs:

if (app.Environment.IsDevelopment())
{
    // Add OpenAPI 3.0 document serving middleware
    // Available at: http://localhost:<port>/swagger/v1/swagger.json
    app.UseOpenApi();

    // Add web UIs to interact with the document
    // Available at: http://localhost:<port>/swagger
    app.UseSwaggerUi(); // UseSwaggerUI is called only in Development.
    
    // Add ReDoc UI to interact with the document
    // Available at: http://localhost:<port>/redoc
    app.UseReDoc(options =>
    {
        options.Path = "/redoc";
    });
}

Execute o aplicativo e navegue até http://localhost:<port>/redoc para visualizar a interface do usuário do Redoc:

Documentação do Redoc para a API de Exemplo.

Por Christoph Nienaber, Rico Suter e Dave Brock

Exibir ou baixar código de exemplo (como baixar)

NSwag oferece os seguintes recursos:

  • A capacidade de utilizar a interface do usuário do Swagger e o gerador do Swagger.
  • Recursos flexíveis de geração de código.

Com o NSwag, você não precisa de uma API existente, pois pode usar APIs de terceiros que incorporam o Swagger e geram uma implementação de cliente. O NSwag permite acelerar o ciclo de desenvolvimento e adaptar-se facilmente às alterações na API.

Registrar o middleware do NSwag

Registre o middleware do NSwag para:

  • Gerar a especificação do Swagger para a API Web implementada.
  • Oferecer a interface do usuário do Swagger para navegar e testar a API Web.

Para usar o middleware ASP.NET Core do NSwag, instale o pacote do NuGet NSwag.AspNetCore. Este pacote contém o middleware para gerar e oferecer a especificação do Swagger, interface do usuário do Swagger (v2 e v3) e a interface do usuário do ReDoc.

Use uma das seguintes abordagens para instalar o pacote do NuGet do NSwag:

  • Da janela Console do Gerenciador de Pacotes:

    • Acesse Exibição>Outras Janelas>Console do Gerenciador de Pacotes

    • Navegue para o diretório no qual o arquivo TodoApi.csproj está localizado

    • Execute o comando a seguir:

      Install-Package NSwag.AspNetCore
      
  • Da caixa de diálogo Gerenciar Pacotes NuGet:

    • Clique com o botão direito do mouse no projeto em Gerenciador de Soluções>Gerenciar Pacotes NuGet
    • Defina a Origem do pacote para "nuget.org"
    • Insira "NSwag.AspNetCore" na caixa de pesquisa
    • Selecione o pacote "NSwag.AspNetCore" na guia Procurar e clique em Instalar

Adicionar e configurar o middleware do Swagger

Realize estas etapas para adicionar e configurar o Swagger em seu aplicativo ASP.NET Core:

  • No método Startup.ConfigureServices, registre os serviços obrigatórios do Swagger:
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<TodoContext>(opt =>
        opt.UseInMemoryDatabase("TodoList"));
    services.AddMvc();

    // Register the Swagger services
    services.AddSwaggerDocument();
}
  • No método Startup.Configure, habilite o middleware para atender à especificação do Swagger gerado e à interface do usuário do Swagger:
public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();

    // Register the Swagger generator and the Swagger UI middlewares
    app.UseOpenApi();
    app.UseOpenApi();
    if (env.IsDevelopment())
    {
        app.UseSwaggerUi3();
    }
    app.UseMvc();
}
  • Inicie o aplicativo. Navegue até:
    • http://localhost:<port>/swagger para exibir a interface do usuário do Swagger.
    • http://localhost:<port>/swagger/v1/swagger.json para exibir a especificação do Swagger.

Geração de código

Você pode tirar proveito dos recursos de geração de código do NSwag, escolhendo uma das opções a seguir:

Gerar o código com NSwagStudio

  • Instale o NSwagStudio, seguindo as instruções no repositório GitHub do NSwagStudio. Na página de versão do NSwag, você pode fazer o download de uma versão xcopy que pode ser iniciada sem privilégios de instalação e administrador.

  • Inicie o NSwagStudio e insira a URL do arquivo swagger.json na caixa de texto URL de Especificação do Swagger. Por exemplo, http://localhost:44354/swagger/v1/swagger.json.

  • Clique no botão Criar Cópia local para gerar uma representação JSON de sua especificação do Swagger.

    Criar uma cópia local da especificação do Swagger

  • Na área Saídas, marque a caixa de seleção Cliente CSharp. Dependendo do seu projeto, você também pode escolher Cliente TypeScript ou Controlador da API Web CSharp. Se você selecionar Controlador da API Web do CSharp, uma especificação de serviço recompilará o serviço, que servirá como uma geração inversa.

  • Clique em Gerar Saídas para produzir uma implementação completa de cliente em C# do projeto TodoApi.NSwag. Para ver o código de cliente gerado, clique na guia Cliente do CSharp:

//----------------------
// <auto-generated>
//     Generated using the NSwag toolchain v12.0.9.0 (NJsonSchema v9.13.10.0 (Newtonsoft.Json v11.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------

namespace MyNamespace
{
    #pragma warning disable

    [System.CodeDom.Compiler.GeneratedCode("NSwag", "12.0.9.0 (NJsonSchema v9.13.10.0 (Newtonsoft.Json v11.0.0.0))")]
    public partial class TodoClient
    {
        private string _baseUrl = "https://localhost:44354";
        private System.Net.Http.HttpClient _httpClient;
        private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;

        public TodoClient(System.Net.Http.HttpClient httpClient)
        {
            _httpClient = httpClient;
            _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(() =>
            {
                var settings = new Newtonsoft.Json.JsonSerializerSettings();
                UpdateJsonSerializerSettings(settings);
                return settings;
            });
        }

        public string BaseUrl
        {
            get { return _baseUrl; }
            set { _baseUrl = value; }
        }

        // code omitted for brevity

Dica

O código do cliente C# é gerado com base em seleções na guia Configurações. Modifique as configurações para executar tarefas como renomenclatura de namespace padrão e geração de método síncrono.

  • Copie o código C# gerado em um arquivo no projeto do cliente que consumirá a API.
  • Inicie o consumo da API Web:
 var todoClient = new TodoClient();

// Gets all to-dos from the API
 var allTodos = await todoClient.GetAllAsync();

 // Create a new TodoItem, and save it via the API.
var createdTodo = await todoClient.CreateAsync(new TodoItem());

// Get a single to-do by ID
var foundTodo = await todoClient.GetByIdAsync(1);

Personalizar a documentação da API

O Swagger fornece opções para documentar o modelo de objeto para facilitar o consumo da API Web.

Descrição e informações da API

No método Startup.ConfigureServices, uma ação de configuração passada para o método AddSwaggerDocument adiciona informações como o autor, a licença e a descrição:

services.AddSwaggerDocument(config =>
{
    config.PostProcess = document =>
    {
        document.Info.Version = "v1";
        document.Info.Title = "ToDo API";
        document.Info.Description = "A simple ASP.NET Core web API";
        document.Info.TermsOfService = "None";
        document.Info.Contact = new NSwag.OpenApiContact
        {
            Name = "Shayne Boyer",
            Email = string.Empty,
            Url = "https://twitter.com/spboyer"
        };
        document.Info.License = new NSwag.OpenApiLicense
        {
            Name = "Use under LICX",
            Url = "https://example.com/license"
        };
    };
});

A interface do usuário do Swagger exibe as informações da versão:

Interface do usuário do Swagger com informações de versão

Comentários XML

Para habilitar os comentários XML, execute as seguintes etapas:

  • Clique com o botão direito do mouse no projeto em Gerenciador de Soluções e selecione Edit <project_name>.csproj.
  • Adicione manualmente as linhas realçadas ao arquivo .csproj:
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

Anotações de dados

Como o NSwag usa Reflexão, e o tipo de retorno recomendado para as ações da API Web é ActionResult<T>, ele só consegue inferir o tipo de retorno definido por T. Não é possível inferir automaticamente outros tipos de retorno possíveis.

Considere o seguinte exemplo:

[HttpPost]
public ActionResult<TodoItem> Create(TodoItem item)
{
    _context.TodoItems.Add(item);
    _context.SaveChanges();

    return CreatedAtRoute("GetTodo", new { id = item.Id }, item);
}

A ação anterior retorna ActionResult<T>. Dentro da ação, ela está retornando CreatedAtRoute. Como o controlador tem o atributo [ApiController], uma resposta BadRequest também é possível. Para obter mais informações, veja Respostas automáticas HTTP 400. Use anotações de dados para informar aos clientes quais códigos de status HTTP esta ação costuma retornar. Marque a ação com os seguintes atributos:

[ProducesResponseType(StatusCodes.Status201Created)]     // Created
[ProducesResponseType(StatusCodes.Status400BadRequest)]  // BadRequest

No ASP.NET Core 2.2 ou posterior, é possível usar as convenções em vez de decorar explicitamente as ações individuais com [ProducesResponseType]. Para obter mais informações, confira Usar convenções da API Web.

O gerador do Swagger agora pode descrever essa ação precisamente e os clientes gerados conseguem saber o que recebem ao chamar o ponto de extremidade. Recomendamos marcar todas as ações com esses atributos.

Para obter diretrizes sobre quais respostas HTTP suas ações de API devem retornar, consulte RFC 9110: Semântica HTTP (Seção 9.3. Definições de método).