Compartilhar via


Tutorial: Gerar um cliente da API REST

Um aplicativo que consome uma API REST é um cenário muito comum. Normalmente, você precisa gerar o código do cliente que seu aplicativo pode usar para chamar a API REST. Neste tutorial, você aprenderá a gerar o cliente da API REST automaticamente durante o processo de build usando o MSBuild. Você usará NSwag, uma ferramenta que gera o código do cliente para uma API REST.

O código de exemplo completo está disponível na geração de cliente da API REST, no repositório de exemplos do .NET no GitHub.

O exemplo mostra um aplicativo de console que consome a API pública Pet Store, que publica uma especificação OpenAPI.

O tutorial pressupõe conhecimento básico de termos do MSBuild, como tarefas, destinos, propriedades ou runtimes; para obter o contexto necessário, consulte o artigo sobre conceitos do MSBuild .

Quando você deseja executar uma ferramenta de linha de comando como parte de um build, há duas abordagens a serem consideradas. Uma delas é usar a tarefa MSBuild Exec, que permite executar uma ferramenta de linha de comando e especificar seus parâmetros. O outro método é criar uma tarefa personalizada derivada de ToolTask, o que oferece maior controle.

Pré-requisitos

Você deve ter uma compreensão dos conceitos do MSBuild, como tarefas, destinos e propriedades. Confira Conceitos do MSBuild.

Os exemplos exigem o MSBuild, que é instalado com o Visual Studio, mas também pode ser instalado separadamente. Confira Baixar o MSBuild sem o Visual Studio.

Opção 1: tarefa Exec

A tarefa exec simplesmente invoca o processo especificado com os argumentos especificados, aguarda a conclusão e retorna true se o processo for concluído com êxito e false se ocorrer um erro.

A geração de código NSwag pode ser usada do MSBuild; consulte NSwag.MSBuild .

O código completo está na pasta PetReaderExecTaskExample; você pode baixar e dar uma olhada. Neste tutorial, você passará passo a passo e aprenderá os conceitos a caminho.

  1. Crie um novo aplicativo de console chamado PetReaderExecTaskExample. Use o .NET 6.0 ou posterior.

  2. Crie outro projeto na mesma solução: PetShopRestClient (essa solução conterá o cliente gerado como uma biblioteca). Para este projeto, use o .NET Standard 2.1. O cliente gerado não é compilado no .NET Standard 2.0.

  3. No projeto PetReaderExecTaskExample, adicione uma dependência de projeto ao projeto PetShopRestClient.

  4. No projeto PetShopRestClient, inclua os seguintes pacotes NuGet:

    • Nswag.MSBuild, que permite o acesso ao gerador de código do MSBuild
    • Newtonsoft.Json, necessário para compilar o cliente gerado
    • System.ComponentModel.Annotations, necessário para compilar o cliente gerado
  5. No projeto PetShopRestClient, adicione uma pasta (denominada PetShopRestClient) para a geração de código e exclua o Class1.cs gerado automaticamente.

  6. Crie um arquivo de texto chamado petshop-openapi-spec.json na raiz do projeto. Copie a especificação OpenAPI de aqui e salve-a no arquivo. É melhor copiar uma captura da especificação em vez de lê-la online durante a construção. Você sempre deseja um build reproduzível consistentemente que dependa apenas da entrada. Consumir a API diretamente pode transformar um build que funciona hoje em um build que falha amanhã da mesma origem. O instantâneo salvo em petshop-openapi-spec.json nos permitirá ainda ter uma versão que seja compilada mesmo se a especificação for alterada.

  7. Em seguida, modifique PetShopRestClient.csproj e adicione destinos do MSBuild para gerar o cliente durante o processo de build.

    Primeiro, adicione algumas propriedades úteis para a geração do cliente:

     <PropertyGroup>
         <PetOpenApiSpecLocation>petshop-openapi-spec.json</PetOpenApiSpecLocation>
         <PetClientClassName>PetShopRestClient</PetClientClassName>
         <PetClientNamespace>PetShopRestClient</PetClientNamespace>
         <PetClientOutputDirectory>PetShopRestClient</PetClientOutputDirectory>
     </PropertyGroup>
    

    Adicione os seguintes destinos:

     <Target Name="generatePetClient" BeforeTargets="CoreCompile" Inputs="$(PetOpenApiSpecLocation)" Outputs="$(PetClientOutputDirectory)\$(PetClientClassName).cs">
         <Exec Command="$(NSwagExe) openapi2csclient /input:$(PetOpenApiSpecLocation)  /classname:$(PetClientClassName) /namespace:$(PetClientNamespace) /output:$(PetClientOutputDirectory)\$(PetClientClassName).cs" ConsoleToMSBuild="true">
         <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
       </Exec>
     </Target>
     <Target Name="forceReGenerationOnRebuild" AfterTargets="CoreClean">
        <Delete Files="$(PetClientOutputDirectory)\$(PetClientClassName).cs"></Delete>
     </Target>
    

    Observe que esse destino usa os atributos BeforeTarget e AfterTarget como forma de definir a ordem de build. O primeiro destino chamado generatePetClient será executado antes do destino de compilação principal, portanto, a origem será criada antes da execução do compilador. O parâmetro de entrada e saída está relacionado ao Build Incremental. O MSBuild pode comparar os carimbos de data/hora dos arquivos de entrada com os carimbos de data/hora dos arquivos de saída e determinar se deve ignorar, compilar ou recompilar parcialmente um destino.

    Depois de instalar o pacote NuGet NSwag.MSBuild em seu projeto, você pode usar a variável $(NSwagExe) em seu arquivo .csproj para executar a ferramenta de linha de comando NSwag em um destino MSBuild. Dessa forma, as ferramentas podem ser facilmente atualizadas por meio do NuGet. Aqui, você está usando a tarefa Exec MSBuild para executar o programa NSwag com os parâmetros necessários para gerar a API Rest do cliente. Confira Comando NSwag e parâmetros.

    Você pode capturar a saída de <Exec> adicionando ConsoleToMsBuild="true" à tag <Exec> e capturando a saída usando o parâmetro ConsoleOutput em uma tag de <Output>. ConsoleOutput devolve o resultado como Item. O espaço em branco é cortado. ConsoleOutput é habilitado quando ConsoleToMSBuild é verdadeiro.

    O segundo destino chamado forceReGenerationOnRebuild exclui a classe gerada durante a limpeza para forçar a regeneração do código gerado durante a execução do destino de recompilação. Esse destino é executado após o destino predefinido CoreClean do MSBuild.

  8. Execute uma recompilação da Solução do Visual Studio e veja o cliente gerado na pasta PetShopRestClient.

  9. Agora, use o cliente gerado. Vá para o Program.csdo cliente e copie o seguinte código:

    using System;
    using System.Net.Http;
    
    namespace PetReaderExecTaskExample
    {
       internal class Program
       {
           private const string baseUrl = "https://petstore.swagger.io/v2";
           static void Main(string[] args)
           {
               HttpClient httpClient = new HttpClient();
               httpClient.BaseAddress = new Uri(baseUrl);
               var petClient = new PetShopRestClient.PetShopRestClient(httpClient);
               var pet = petClient.GetPetByIdAsync(1).Result;
               Console.WriteLine($"Id: {pet.Id} Name: {pet.Name} Status: {pet.Status} CategoryName: {pet.Category.Name}");
           }
       }
    }
    

    Nota

    Esse código usa new HttpClient() porque é simples de demonstrar, mas não é a melhor prática para o código do mundo real. A melhor prática é usar HttpClientFactory para criar um objeto HttpClient que resolva os problemas conhecidos de HttpClient solicitação, como Esgotamento de Recursos ou problemas de DNS obsoletos. Confira Usar IHttpClientFactory para implementar solicitações HTTP resilientes.

Parabéns! Agora, você pode executar o programa para ver como ele funciona.

Opção 2: tarefa personalizada derivada de ToolTask

Em muitos casos, usar a tarefa Exec é bom o suficiente para executar uma ferramenta externa para fazer algo como a geração de código do cliente da API REST, mas e se você quiser permitir a geração de código do cliente da API REST se e somente se você não usar um caminho absoluto do Windows como entrada? Ou e se você precisar calcular de alguma forma onde o executável está? Quando há qualquer situação em que você precisa executar algum código para executar um trabalho adicional, a Tarefa da Ferramenta MSBuild é a melhor solução. A classe ToolTask é uma classe abstrata derivada do MSBuild Task. Você pode definir uma subclasse concreta, que cria uma tarefa personalizada do MSBuild. Essa abordagem permite executar qualquer código necessário para se preparar para a execução do comando. Você deve ler o tutorial Criar uma tarefa personalizada para a geração de código primeiro.

Você criará uma tarefa personalizada derivada de do MSBuild ToolTask que gerará um cliente da API REST, mas ela será projetada para emitir um erro se você tentar referenciar a especificação OpenAPI usando um endereço http. O NSwag dá suporte a um endereço http como entrada de especificação OpenAPI, mas para fins deste exemplo, vamos supor que haja um requisito de design para não permitir isso.

O código completo está nesta pasta PetReaderToolTaskExample; você pode baixar e dar uma olhada. Neste tutorial, você passará passo a passo e aprenderá alguns conceitos que podem ser aplicados aos seus próprios cenários.

  1. Crie um novo Projeto do Visual Studio para a tarefa personalizada. Chame-o RestApiClientGenerator e use o modelo de da Biblioteca de Classes (C#) com o .NET Standard 2.0. Nomeie a solução PetReaderToolTaskExample.

  2. Excluir Class1.cs, que foi gerado automaticamente.

  3. Adicione os pacotes NuGet Microsoft.Build.Utilities.Core:

    • Criar uma classe chamada RestApiClientGenerator

    • Herda do MSBuild ToolTask e implemente o método abstrato, conforme mostrado no seguinte código:

      using Microsoft.Build.Utilities;
      
      namespace RestApiClientGenerator
      {
          public class RestApiClientGenerator : ToolTask
          {
              protected override string ToolName => throw new System.NotImplementedException();
      
              protected override string GenerateFullPathToTool()
              {
                  throw new System.NotImplementedException();
              }
          }
      }
      
  4. Adicione os seguintes parâmetros:

    • InputOpenApiSpec, onde a especificação é
    • ClientClassName, nome da classe gerada
    • ClientNamespaceName, namespace em que a classe é gerada
    • FolderClientClass, caminho para a pasta em que a classe estará localizada
    • NSwagCommandFullPath, caminho completo para o diretório onde NSwag.exe está localizado
         [Required]
         public string InputOpenApiSpec { get; set; }
         [Required]
         public string ClientClassName { get; set; }
         [Required]
         public string ClientNamespaceName { get; set; }
         [Required]
         public string FolderClientClass { get; set; }
         [Required]
         public string NSwagCommandFullPath { get; set; }
    
  5. Instale a ferramenta de linha de comando NSwag. Você precisará do caminho completo para o diretório onde NSwag.exe está localizado.

  6. Implemente os métodos abstratos:

       protected override string ToolName => "RestApiClientGenerator";
    
       protected override string GenerateFullPathToTool()
       {
           return $"{NSwagCommandFullPath}\\NSwag.exe";
       }
    
  7. Há muitos métodos que você pode substituir. Para a implementação atual, defina estes dois:

    • Defina o parâmetro de comando:
      protected override string GenerateCommandLineCommands()
      {
          return $"openapi2csclient /input:{InputOpenApiSpec}  /classname:{ClientClassName} /namespace:{ClientNamespaceName} /output:{FolderClientClass}\\{ClientClassName}.cs";
      }
    
    • Validação de parâmetro:
    protected override bool ValidateParameters()
    {
          //http address is not allowed
          var valid = true;
          if (InputOpenApiSpec.StartsWith("http:") || InputOpenApiSpec.StartsWith("https:"))
          {
              valid = false;
              Log.LogError("URL is not allowed");
          }
    
          return valid;
    }
    

    Nota

    Essa validação simples pode ser feita de outra forma no arquivo MSBuild, mas é recomendável fazer isso no código C# e encapsular o comando e a lógica.

  8. Compile o projeto.

Criar um aplicativo de console para usar a nova tarefa do MSBuild

A próxima etapa é criar um aplicativo que use a tarefa.

  1. Crie um projeto de Aplicativo de Console e nomeie-o PetReaderToolTaskConsoleApp. Escolha .NET 6.0. Marque-o como projeto inicial.

  2. Crie um projeto da Biblioteca de Classes para gerar o código, chamado PetRestApiClient. Utilize o .NET Standard 2.1.

  3. No projeto PetReaderToolTaskConsoleApp, crie uma dependência de projeto para PetRestApiClient.

  4. No projeto PetRestApiClient, crie uma pasta PetRestApiClient. Essa pasta conterá o código gerado.

  5. Excluir Class1.cs, que foi gerado automaticamente.

  6. No PetRestApiClient, adicione os seguintes pacotes NuGet:

    • Newtonsoft.Json, necessário para compilar o cliente gerado
    • System.ComponentModel.Annotations, necessário para compilar o cliente gerado
  7. No projeto PetRestApiClient, crie um arquivo de texto chamado petshop-openapi-spec.json (na pasta do projeto). Para adicionar a especificação OpenAPI, copie o conteúdo de aqui no arquivo. Gostamos de um build reproduzível que depende apenas da entrada, conforme discutido anteriormente. Neste exemplo, você gerará um erro de build se um usuário escolher uma URL como a entrada de especificação OpenAPI.

    Importante

    Uma reconstrução geral não funcionará. Você verá erros que indicam que não é possível copiar ou excluir RestApiClientGenerator.dll'. Isso ocorre porque ele está tentando criar a tarefa personalizada do MBuild no mesmo processo de build que a usa. Selecione PetReaderToolTaskConsoleApp e recompile somente esse projeto. A outra solução é colocar a tarefa personalizada em uma solução completamente independente do Visual Studio, como você fez em Tutorial: Criar uma tarefa personalizada exemplo.

  8. Copie o seguinte código para Program.cs:

     using System;
     using System.Net.Http;
     namespace PetReaderToolTaskConsoleApp
     {
       internal class Program
       {
           private const string baseUrl = "https://petstore.swagger.io/v2";
           static void Main(string[] args)
           {
               HttpClient httpClient = new HttpClient();
               httpClient.BaseAddress = new Uri(baseUrl);
               var petClient = new PetRestApiClient.PetRestApiClient(httpClient);
               var pet = petClient.GetPetByIdAsync(1).Result;
               Console.WriteLine($"Id: {pet.Id} Name: {pet.Name} Status: {pet.Status} CategoryName: {pet.Category.Name}");
           }
       }
     }
    
  9. Altere as instruções do MSBuild para chamar a tarefa e gerar o código. Edite PetRestApiClient.csproj seguindo estas etapas:

    1. Registre o uso da tarefa personalizada do MSBuild:

      <UsingTask TaskName="RestApiClientGenerator.RestApiClientGenerator" AssemblyFile="..\RestApiClientGenerator\bin\Debug\netstandard2.0\RestApiClientGenerator.dll" />
      
    2. Adicione algumas propriedades necessárias para executar a tarefa:

       <PropertyGroup>
          <!--The place where the OpenAPI spec is in-->
         <PetClientInputOpenApiSpec>petshop-openapi-spec.json</PetClientInputOpenApiSpec>
         <PetClientClientClassName>PetRestApiClient</PetClientClientClassName>
         <PetClientClientNamespaceName>PetRestApiClient</PetClientClientNamespaceName>
         <PetClientFolderClientClass>PetRestApiClient</PetClientFolderClientClass>
         <!--The directory where NSawg.exe is in-->
         <NSwagCommandFullPath>C:\Nsawg\Win</NSwagCommandFullPath>
        </PropertyGroup>
      

      Importante

      Selecione o valor de NSwagCommandFullPath adequado com base no local de instalação em seu sistema.

    3. Adicione um destino do MSBuild para gerar o cliente durante o processo de compilação. Esse destino deve ser executado antes que CoreCompile seja executado para gerar o código usado na compilação.

      <Target Name="generatePetClient" BeforeTargets="CoreCompile" Inputs="$(PetClientInputOpenApiSpec)" Outputs="$(PetClientFolderClientClass)\$(PetClientClientClassName).cs">
        <!--Calling our custom task derivated from MSBuild Tool Task-->
        <RestApiClientGenerator InputOpenApiSpec="$(PetClientInputOpenApiSpec)" ClientClassName="$(PetClientClientClassName)" ClientNamespaceName="$(PetClientClientNamespaceName)" FolderClientClass="$(PetClientFolderClientClass)" NSwagCommandFullPath="$(NSwagCommandFullPath)"></RestApiClientGenerator>
      </Target>
      
      <Target Name="forceReGenerationOnRebuild" AfterTargets="CoreClean">
        <Delete Files="$(PetClientFolderClientClass)\$(PetClientClientClassName).cs"></Delete>
      </Target>
      

    Input e Output estão relacionados ao Build Incremental, e o destino forceReGenerationOnRebuild exclui o arquivo gerado após CoreClean, o que força o cliente a ser regenerado durante a operação de rebuild.

  10. Selecione PetReaderToolTaskConsoleApp e recompile somente esse projeto. Agora, o código do cliente é gerado e o código é compilado. Você pode executá-lo e ver como ele funciona. Esse código gera o código de um arquivo e isso é permitido.

  11. Nesta etapa, você demonstrará a validação do parâmetro. Em PetRestApiClient.csproj, altere a propriedade $(PetClientInputOpenApiSpec) para usar a URL:

      <PetClientInputOpenApiSpec>https://petstore.swagger.io/v2/swagger.json</PetClientInputOpenApiSpec>
    
  12. Selecione PetReaderToolTaskConsoleApp e recompile somente esse projeto. Você receberá o erro" "A URL não é permitida" de acordo com o requisito de design.

Baixar o código

Instale a ferramenta de linha de comando NSwag. Em seguida, você precisará do caminho completo para o diretório onde NSwag.exe está localizado. Depois disso, edite PetRestApiClient.csproj e selecione o valor de $(NSwagCommandFullPath) adequado com base no caminho de instalação em seu computador. Agora, selecione RestApiClientGenerator e crie apenas esse projeto e, por fim, selecione e recompile PetReaderToolTaskConsoleApp. Você pode executar PetReaderToolTaskConsoleApp. para verificar se tudo funciona conforme o esperado.

Próximas etapas

Talvez você queira publicar sua tarefa personalizada como um pacote NuGet.

Ou saiba como testar uma tarefa personalizada.