Desenvolvimento Back-end .NET Core

Gerando APIs clients com as ferramentas de OpenAPI do .NET

Aprenda como gerar APIs clientes com a global tool Microsoft.dotnet-openapi.

há 3 anos 1 mês

Formação Especialista ASP.NET Core
Conheça a formação em detalhes

Se for necessário consumir os dados de uma API, como vimos, este processo pode ser facilitado com o uso da biblioteca Flurl. Mesmo não sendo complexo, ainda irá requerer códigos redundantes e qualquer alteração na API, irá necessitar de modificações no client. Entretanto, este processo pode ser facilitado e praticamente automatizado com uso das ferramentas de OpenAPI do .NET.

OpenAPI

Quase sinônimo de Swagger, OpenAPI é uma série de especificações definidas pela comunidade em conjunto com a Open API Iniciative, para descrição e documentação de APIs.

Totalmente independente de uma linguagem de programação, a especificação OpenAPI permite que tanto humanos quanto aplicações compreendam e explorem um serviço sem necessitar ter acesso ao seu código fonte ou documentação adicional.

Quando corretamente definida, um consumidor poderá interagir com o serviço utilizando uma implementação simples ou nenhuma dependendo das ferramentas utilizadas.

Microsoft.dotnet-openapi

Por permitir definir todos os aspectos da API, algumas ferramentas conseguem gerar clients ao analisar uma especificação OpenAPI. Uma ferramenta clássica que faz este tipo de procedimento é o Swagger, que disponibiliza uma interface para uma análise visual e testável da especificação.

Já outras ferramentas geram códigos que podem ser adicionados à uma aplicação. Com isso, o desenvolvedor não precisa se preocupar em implementar o client da API no projeto. Para o .NET uma ferramenta clássica que realiza este tipo de procedimento é a NSwag, entretanto, na versão 5 desta biblioteca, a Microsoft disponibiliza a ferramenta Microsoft.dotnet-openapi que também realiza este procedimento.

Esta global tool cria todo o código necessário para consumir os dados de uma API de acordo com a especificação OpenAPI indicada. Caso haja alguma alteração na especificação, ela também pode ser utilizada para atualizar os códigos. Com isso, o desenvolvedor não precisa digitar nenhuma linha para poder consumir os dados da API.

Api de exemplo

Para exemplificar a ferramenta Microsoft.dotnet-openapi, irei utilizar a especificação OpenAPI gerada pela API criada com a biblioteca Carter, pois ela está completa e não requer nenhuma modificação.

Caso queira utilizá-la você pode obter o projeto no meu Github.

Gerando os códigos do client

Neste exemplo o client será definido em uma aplicação à parte da API, entretanto, nada impede que ele seja definido no mesmo projeto, ou dentro da mesma solução.

Assim, inicialmente será criado um projeto console:

dotnet new console -n OpenAPiClient

Em seguida, adicione a global tool:

dotnet tool install -g Microsoft.dotnet-openapi

Com isso, no nível do arquivo de configuração do projeto (*.csproj), execute o comando abaixo:

dotnet openapi add url https://localhost:5001/openapi --output-file CarterApi.json

Por ser uma URL, acima é utilizado o add url. Caso queira especificar um arquivo de configuração, pode ser utilizado o comando add file, e.g.:

dotnet openapi add file CarterApi.json

O comando add url irá baixar da url informada a especificação OpenAPI e irá salvar uma cópia dela no projeto:

Explorer do VS Code mostrando um projeto console com destaque no arquivo CarterApi.json

E no arquivo de configuração dele, será adicionado a configuração abaixo:

<ItemGroup>
  <OpenApiReference Include="CarterApi.json" SourceUrl="https://localhost:5001/openapi" />
</ItemGroup>

Assim, caso queira, isso pode ser definido manualmente.

Se não quiser utilizar a ferramenta de linha de comando, no Visual Studio Community (Professional e Enterprise), isso também pode ser definido com a opção “Connected Service” (Add > Connected Service, ao clicar com o botão direito do mouse sobre projeto).

Com esta configuração, a ferramenta já criará os códigos necessários para se conectar à API:

class Program
{
    static async Task Main(string[] args)
    {
        using var httpClient = new HttpClient();

        var apiClient = new CarterApiClient("https://localhost:5001", httpClient);
        
        await apiClient.PostPessoaAsync(new Pessoa{
            Id = 1,
            Nome = "Carlos",
            Idade = 33
        });

        await apiClient.PostPessoaAsync(new Pessoa{
            Id = 2,
            Nome = "Maria",
            Idade = 33
        });
        var pessoas = await apiClient.GetPessoaAsync();

        foreach(var pessoa in pessoas)
        {
            Console.WriteLine($"{pessoa.Id} - {pessoa.Nome} - {pessoa.Idade}");
        }

        await apiClient.PutPessoaAsync(1, new Pessoa{
            Id = 1,
            Nome = "José",
            Idade = 12
        });

        var jose = await apiClient.GetPessoaByIdAsync(1);

        Console.WriteLine($"{jose.Id} - {jose.Nome} - {jose.Idade}");

        await apiClient.DeletePessoaAsync(1);

        pessoas = await apiClient.GetPessoaAsync();

        foreach(var pessoa in pessoas)
        {
            Console.WriteLine($"{pessoa.Id} - {pessoa.Nome} - {pessoa.Idade}");
        }
    }
}

O nome do client sempre será o mesmo nome do arquivo de configuração definido no projeto, seguindo de Client:

var apiClient = new CarterApiClient("https://localhost:5001", httpClient);

O nome padrão é OpenApiClient.

Note que ele também criou classes equivalentes as consumidas pela api:

await apiClient.PostPessoaAsync(new Pessoa{
    Id = 1,
    Nome = "Carlos",
    Idade = 33
});

Por fim, o nome dos métodos serão criados de acordo com o atributo operationId da operação definida na especificação do OpenAPI:

{
  "openapi": "3.0.1",
  "info": {
    "title": "Carter <3 OpenApi",
    "version": "3.0.0"
  },
  "paths": {
    "/pessoa": {
      "post": {
        "tags": [
          "Pessoa"
        ],
        "description": "Adiciona uma pessoa",
        "operationId": "Pessoa_PostPessoa",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Pessoa"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pessoa adicionada"
          }
        }
      }
    },
  }
}

Atualizando configuração

Caso a configuração esteja definindo um arquivo do disco. Este pode ser gerado pelo próprio projeto ou outro da solução. Sempre que for modificado, a ferramenta irá gerar um novo client.

Se for o arquivo de uma API online, como no caso deste artigo, quando ela for modificada, é necessário atualizar o arquivo do projeto. Isso pode ser feito com o comando refresh:

dotnet openapi refresh https://localhost:5001/openapi  

E caso queria, a configuração pode ser removida com o comando remove:

dotnet openapi remove CarterApi.json

Finalizando

O Microsoft.dotnet-openapi é uma ótima ferramenta para a geração de clients de APIs especificadas com o OpenAPI. O seu uso facilita e muito o desenvolvimento, permitindo que o desenvolvedor não precisa se preocupar com a criação de client.

A sua única desvantagem é que não fornece muitas opções de customização do código gerado. Caso queira adicionar algum recurso customizado ao client, é necessário criar uma partial classe e adicionar o recurso nela. Nunca altere o código gerado pela ferramenta, pois ele pode ser recriado quando a API for atualizada.

Autor(a) do artigo

Wladimilson M. Nascimento
Wladimilson M. Nascimento

Instrutor, nerd, cinéfilo e desenvolvedor nas horas vagas. Graduado em Ciências da Computação pela Universidade Metodista de São Paulo.

Todos os artigos

Artigos relacionados Ver todos