Criando Web APIs modernas, autônomas e rastreáveis com .Net Core utilizando arquitetura de microsserviços – Parte 2

Após a conclusão da etapa 1, onde criamos todos os projetos e configuramos a execução do sistema, as funcionalidades básicas de nossas APIs estão todas funcionando perfeitamente. Ao pressionar a tecla F5 para executar os projetos da nossa solução, veremos as seguintes janelas serem abertas no browser: Embora os serviços prometidos estejam funcionando, as informações destas páginas não são nada expressivas para o consumidor de nossas APIs. O que faremos a seguir é habilitar a documentação automática utilizando o NSwag. Para isto, vamos executar os seguintes passos: 1. Instalando o NSwag e criando o configurador do Swagger Acesse o menu Tools ⇒ Nuget Package Manager ⇒ Package Manager Console; Na janela do console, no campo Default Project, selecione o projeto Erp.Shared; Digite o comando Install-Package NSwag.AspNetCore, pressione Enter e aguarde a instalação. Como o projeto Api.Erp.Shared está referenciado em todos os demais projetos, instalaremos o NSwag apenas neste projeto. A seguir, criaremos dois métodos de extensão para configurar o swagger. Crie o seguinte arquivo no diretório Extensions do projeto Api.Erp.Shared: …Api.Erp\Api.Erp.Shared\Extensions\SwaggerConfig.cs using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using System.Reflection; namespace Api.Erp.Shared.Extensions { public static class SwaggerConfig { public static void ConfigureSwaggerDoc(this IServiceCollection services, string description) { services.AddOpenApiDocument(config => { config.Version = "v1"; config.AllowReferencesWithProperties = true; //Habilita a geração de exemplos para propriedades aninhadas config.Title = "Documentação da API: " + Assembly.GetEntryAssembly().GetName().Name; config.Description = description; }); } public static void ConfigureSwaggerUI(this IApplicationBuilder app) { // Ativa o middleware para veicular o Swagger gerado como um terminal JSON. app.UseOpenApi(); // Registra o gerador Swagger e os middlewares Swagger UI app.UseSwaggerUi3(config => config.TransformToExternalPath = (internalUiRoute, request) => { config.Path = "/swagger"; if (internalUiRoute.StartsWith("/") == true && internalUiRoute.StartsWith(request.PathBase) == false) { return request.PathBase + internalUiRoute; } else { return internalUiRoute; } }); } } } 2. Habilitando o Swagger no projeto Api.Erp.Clientes Acesse o arquivo Startup.cs do projeto Api.Erp.Clientes e faça as seguintes alterações: using Api.Erp.Shared.Extensions; public class Startup { … public void ConfigureServices(IServiceCollection services) { … //Habilita o Swagger string description = "**API para gerenciamento dos clientes do sistema Api.Erp**"; services.ConfigureSwaggerDoc(description); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { … // Ativa a Swagger-ui app.ConfigureSwaggerUI(); … } } 3. Habilitando o Swagger no projeto Api.Erp.Comercial Acesse o arquivo Startup.cs do projeto Api.Erp.Comercial e faça as seguintes alterações: using Api.Erp.Shared.Extensions; public class Startup { … public void ConfigureServices(IServiceCollection services) { … //Habilita o Swagger string description = "**API para gerenciamento das vendas do sistema Api.Erp**"; services.ConfigureSwaggerDoc(description); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { … // Ativa a Swagger-ui app.ConfigureSwaggerUI(); … } } 4. Habilitando o Swagger no projeto Api.Erp.Fiscal Acesse o arquivo Startup.cs do projeto Api.Erp.Fiscal e faça as seguintes alterações: using Api.Erp.Shared.Extensions; public class Startup { … public void ConfigureServices(IServiceCollection services) { … //Habilita o Swagger string description = "**API para gerenciamento das notas fiscais do sistema Api.Erp**"; services.ConfigureSwaggerDoc(description); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { … // Ativa a Swagger-ui app.ConfigureSwaggerUI(); … } } A partir deste momento, ao executarmos o nossas APIs (F5), caso acessemos a rota \swagger, as páginas de documentação já serão exibidas. Nestas páginas, é possível testar todos os endpoints, clicando no botão Try it out e depois no botão Execute. Abrindo a rota do Swagger

Mar 6, 2025 - 22:16
 0
Criando Web APIs modernas, autônomas e rastreáveis com .Net Core utilizando arquitetura de microsserviços – Parte 2

Após a conclusão da etapa 1, onde criamos todos os projetos e configuramos a execução do sistema, as funcionalidades básicas de nossas APIs estão todas funcionando perfeitamente.

Ao pressionar a tecla F5 para executar os projetos da nossa solução, veremos as seguintes janelas serem abertas no browser:

Embora os serviços prometidos estejam funcionando, as informações destas páginas não são nada expressivas para o consumidor de nossas APIs.

O que faremos a seguir é habilitar a documentação automática utilizando o NSwag.

Para isto, vamos executar os seguintes passos:

1. Instalando o NSwag e criando o configurador do Swagger

Acesse o menu Tools ⇒ Nuget Package Manager ⇒ Package Manager Console;
Na janela do console, no campo Default Project, selecione o projeto Erp.Shared;
Digite o comando Install-Package NSwag.AspNetCore, pressione Enter e aguarde a instalação.

Como o projeto Api.Erp.Shared está referenciado em todos os demais projetos, instalaremos o NSwag apenas neste projeto.

A seguir, criaremos dois métodos de extensão para configurar o swagger.

Crie o seguinte arquivo no diretório Extensions do projeto Api.Erp.Shared:

…Api.Erp\Api.Erp.Shared\Extensions\SwaggerConfig.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

namespace Api.Erp.Shared.Extensions
{
    public static class SwaggerConfig
    {
        public static void ConfigureSwaggerDoc(this IServiceCollection services, string description)
        {
            services.AddOpenApiDocument(config =>
            {
                config.Version = "v1";
                config.AllowReferencesWithProperties = true; //Habilita a geração de exemplos para propriedades aninhadas
                config.Title = "Documentação da API: " + Assembly.GetEntryAssembly().GetName().Name;
                config.Description = description;
            });
        }

        public static void ConfigureSwaggerUI(this IApplicationBuilder app)
        {
            // Ativa o middleware para veicular o Swagger gerado como um terminal JSON.
            app.UseOpenApi();

            // Registra o gerador Swagger e os middlewares Swagger UI
            app.UseSwaggerUi3(config => config.TransformToExternalPath = (internalUiRoute, request) =>
            {
                config.Path = "/swagger";
                if (internalUiRoute.StartsWith("/") == true && internalUiRoute.StartsWith(request.PathBase) == false)
                {
                    return request.PathBase + internalUiRoute;
                }
                else
                {
                    return internalUiRoute;
                }
            });
        }
    }
}

2. Habilitando o Swagger no projeto Api.Erp.Clientes

Acesse o arquivo Startup.cs do projeto Api.Erp.Clientes e faça as seguintes alterações:

using Api.Erp.Shared.Extensions;
    public class Startup
    {

        public void ConfigureServices(IServiceCollection services)
        {

            //Habilita o Swagger
            string description = "**API para gerenciamento dos clientes do sistema Api.Erp**";
            services.ConfigureSwaggerDoc(description);
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {

            // Ativa a Swagger-ui
            app.ConfigureSwaggerUI();

        }
    }

3. Habilitando o Swagger no projeto Api.Erp.Comercial

Acesse o arquivo Startup.cs do projeto Api.Erp.Comercial e faça as seguintes alterações:

using Api.Erp.Shared.Extensions;
    public class Startup
    {

        public void ConfigureServices(IServiceCollection services)
        {

            //Habilita o Swagger
            string description = "**API para gerenciamento das vendas do sistema Api.Erp**";
            services.ConfigureSwaggerDoc(description);
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {

            // Ativa a Swagger-ui
            app.ConfigureSwaggerUI();

        }
    }

4. Habilitando o Swagger no projeto Api.Erp.Fiscal

Acesse o arquivo Startup.cs do projeto Api.Erp.Fiscal e faça as seguintes alterações:

using Api.Erp.Shared.Extensions;
    public class Startup
    {

        public void ConfigureServices(IServiceCollection services)
        {

            //Habilita o Swagger
            string description = "**API para gerenciamento das notas fiscais do sistema Api.Erp**";
            services.ConfigureSwaggerDoc(description);
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {

            // Ativa a Swagger-ui
            app.ConfigureSwaggerUI();

        }
    }

A partir deste momento, ao executarmos o nossas APIs (F5), caso acessemos a rota \swagger, as páginas de documentação já serão exibidas.

Nestas páginas, é possível testar todos os endpoints, clicando no botão Try it out e depois no botão Execute.

  1. Abrindo a rota do Swagger automaticamente

Você deve ter notado, que ao executar os projetos, ainda está sendo necessário digitar a rota que exibe a documentação do Swagger (\swagger), este processo pode ser automatizado.

Esta ação, também poderia ser feito via configuração nas propriedades do projeto. Porém, faremos de uma forma um pouco mais simples e não baseada em configuração. Siga os seguintes passos:

Crie um arquivo chamado DocsController.cs, na pasta Controller de cada um dos projetos, com os respectivos conteúdos:

…\Api.Erp\Api.Erp.Clientes\Controllers\DocsController.cs

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Api.Erp.Clientes.Controllers
{
    /// 
    /// Controller para exibir a documentação da API de Clientes
    /// 
    [Route("")]
    [ApiExplorerSettings(IgnoreApi = true)]
    public class DocsController : Controller
    {
        [Route(""), HttpGet]
        [AllowAnonymous]
        public IActionResult Swagger()
        {
            return Redirect("~/swagger");
        }
    }
}

…\Api.Erp\Api.Erp.Comercial\Controllers\DocsController.cs

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Api.Erp.Comercial.Controllers
{
    /// 
    /// Controller para exibir a documentação da API Comercial
    /// 
    [Route("")]
    [ApiExplorerSettings(IgnoreApi = true)]
    public class DocsController : Controller
    {
        [Route(""), HttpGet]
        [AllowAnonymous]
        public IActionResult Swagger()
        {
            return Redirect("~/swagger");
        }
    }
}

…\Api.Erp\Api.Erp.Fiscal\Controllers\DocsController.cs

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Api.Erp.Fiscal.Controllers
{
    /// 
    /// Controller para exibir a documentação da API Fiscal
    /// 
    [Route("")]
    [ApiExplorerSettings(IgnoreApi = true)]
    public class DocsController : Controller
    {
        [Route(""), HttpGet]
        [AllowAnonymous]
        public IActionResult Swagger()
        {
            return Redirect("~/swagger");
        }
    }
}

Agora, ao executar a solution (F5), as páginas do swagger serão carregadas automaticamente para todas as APIs, sem a necessidade de acionar a rota \swagger.

6. Melhorando os exemplos de dados gerados do Swagger

Ao examinarmos a documentação de cada endpoint, podemos verificar no campo “Example Value”, um exemplo de dados que poderiam ser submetidos para a API, porém os valor atribuídos à cada propriedade, não são sempre sugestivos para o usuário.

Veja por exemplo o JSON atribuído ao método POST da API que gerencia as notas fiscais:

Podemos melhorar estes exemplos, com a anotação JsonSchemaExtensionData da classe NJsonSchema.Annotations.JsonSchemaExtensionDataAttribute.

Vamos alterar as nossas classes, incluindo exemplos de dados mais eficientes, incluindo também a tag com um texto explicativo para o usuário (internos ou externos) de nossas APIs.

Faça as seguintes alterações nos respectivos arquivos:

…Api.Erp\Api.Erp.Shared\ViewModels\ClienteVM.cs

using NJsonSchema.Annotations;
using System;

namespace Api.Erp.Shared.ViewModels
{
    /// 
    /// Informações para o cadastro do cliente
    /// 
    public class ClienteVM
    {
        /// 
        /// Id do cliente no Banco de Dados
        /// 
        [JsonSchemaExtensionData("example", "15")]
        public string id { get; set; }

        /// 
        /// Nome do cliente
        /// 
        [JsonSchemaExtensionData("example", "Nome do cliente")]
        public string nome { get; set; }

        /// 
        /// Email do cliente
        /// 
        [JsonSchemaExtensionData("example", "emaildocliente@provedor.com.br")]
        public string email { get; set; }
    }
}

** …Api.Erp\Api.Erp.Shared\ViewModels\NotaFiscalVmInput.cs**

using NJsonSchema.Annotations;

namespace Api.Erp.Shared.ViewModels
{    
    /// 
    /// Informações para geração de uma nova nota fiscal
    /// 
    public class NotaFiscalVmInput
    {
        /// 
        /// Id na Nota Fiscal no Banco de Dados
        /// 
        [JsonSchemaExtensionData("example", "31")]
        public string id { get; set; }

        /// 
        /// Id da venda que será a origem da Nota Fiscal
        /// 
        [JsonSchemaExtensionData("example", "2")]
        public string idVenda { get; set; }

        /// 
        /// Valor total do ICMS. Formato 00000.00
        /// 
        [JsonSchemaExtensionData("example", 1500.90)]
        public decimal valorTotalICMS { get; set; }

        /// 
        /// Valor total da nota fiscal
        /// 
        [JsonSchemaExtensionData("example", 1500.00)]
        public decimal valorTotalNotaFiscal { get; set; }
    }
}

…Api.Erp\Api.Erp.Shared\ViewModels\NotaFiscalVmOutput.cs

namespace Api.Erp.Shared.ViewModels
{
    /// 
    /// Informações da nota fiscal
    /// 
    public class NotaFiscalVmOutput
    {
        /// 
        /// Id na Nota Fiscal no Banco de Dados
        /// 
        public string id { get; set; }

        /// 
        /// Referência para a venda que originou a nota fiscal
        /// 
        public VendaVmOutput Venda { get; set; }

        /// 
        /// Valor total do ICMS
        /// 
        public decimal valorTotalICMS { get; set; }

        /// 
        /// Valor total da nota fiscal
        /// 
        public decimal valorTotalNotaFiscal { get; set; }
    }
}

…Api.Erp\Api.Erp.Shared\ViewModels\VendaVmInput.cs

using NJsonSchema.Annotations;

namespace Api.Erp.Shared.ViewModels
{
    /// 
    /// Informações para geração de uma nova venda
    /// 
    public class VendaVmInput
    {
        /// 
        /// Id na venda no banco de dados
        /// 
        [JsonSchemaExtensionData("example", "3")]
        public string id { get; set; }

        /// 
        /// Id do cliente da venda
        /// 
        [JsonSchemaExtensionData("example", "10")]
        public string idCliente { get; set; }

        /// 
        /// Valor total da venda. Formato 00000.00
        /// 
        [JsonSchemaExtensionData("example", 890.50)]
        public decimal valorTotal { get; set; }
    }
}

…Api.Erp\Api.Erp.Shared\ViewModels\VendaVmOutput.cs

namespace Api.Erp.Shared.ViewModels
{
    /// 
    /// Informações da venda
    /// 
    public class VendaVmOutput
    {
        /// 
        /// Id na venda no banco de dados
        /// 
        public string id { get; set; }

        /// 
        /// Referência para o cliente, para o qual foi executada a venda
        /// 
        public ClienteVM cliente { get; set; }

        /// 
        /// Valor total da venda
        /// 
        public decimal valorTotal { get; set; }
    }
}

As informações incluídas na anotação** [JsonSchemaExtensionData("example", "value")]** serão utilizadas para a geração dos exemplos de dados na interface do Swagger, porém, para aproveitar as informações incluídas na tag precisamos configurar os nossos projetos para gerar o arquivo XML da documentação (XML Documentation file). Uma maneira muito simples de fazer isso, é editar os arquivos de nossos projetos (extensão .csproj) e incluir as instruções:

   Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
       bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
  

   Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
       bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
  

Portanto, dê um clique duplo em cada um dos arquivos de cada projeto (.csproj) e deixe-os da seguinte forma:

…Api.Erp\Api.Erp.Clientes\Api.Erp.Clientes.csproj

 Sdk="Microsoft.NET.Sdk.Web">

  
    netcoreapp3.1
  

   Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
  

   Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
  

  
     Include="..\Api.Erp.Shared\Api.Erp.Shared.csproj" />
  


…Api.Erp\Api.Erp.Comercial\Api.Erp.Comercial.csproj

 Sdk="Microsoft.NET.Sdk.Web">

  
    netcoreapp3.1
  

   Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
  

   Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
  

  
     Include="..\Api.Erp.Shared\Api.Erp.Shared.csproj" />
  


…Api.Erp\Api.Erp.Fiscal\Api.Erp.Fiscal.csproj

 Sdk="Microsoft.NET.Sdk.Web">

  
    netcoreapp3.1
  

   Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
  

   Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
  

  
     Include="..\Api.Erp.Shared\Api.Erp.Shared.csproj" />
  


…Api.Erp\Api.Erp.Shared\Api.Erp.Shared.csproj

 Sdk="Microsoft.NET.Sdk">

  
    netcoreapp3.1
  

   Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
  

   Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
  

  
     Include="NSwag.AspNetCore" Version="13.3.0" />
  


Ao executarmos nossas APIs, agora teremos uma riqueza muito maior de detalhes, com instruções precisas para os usuários.

Veja novamente o exemplo do endpoit utilizado para criar uma nova nota fiscal, após as modificações:

Com isto concluímos a parte 2 desta série de artigos.

Obtenha o código completo da solução até o presente momento neste repositório do GitHub.

Links para a série completa:

Criando Web APIs modernas, autônomas e rastreáveis com .Net Core utilizando arquitetura de microsserviços – (Parte 1) Construindo o projeto

Criando Web APIs modernas, autônomas e rastreáveis com .Net Core utilizando arquitetura de microsserviços – (Parte 2) Incluindo documentação com o Swagger

Criando Web APIs modernas, autônomas e rastreáveis com .Net Core utilizando arquitetura de microsserviços (Parte 3) – Implementando rastreamento distribuído