ASP .NET Core - Consumindo uma API de terceiros


 Hoje veremos como consumir uma API de terceiros em uma aplicação ASP .NET Core criada no .NET 6.0.

Nas aplicações web modernas é muito comum usar API de terceiros para aprimorar a funcionalidade do aplicativo. Existem milhares de APIs gratuitas e comerciais disponíveis e se você sabe como consumir essas APIs em seus aplicativos ASP.NET Core, pode construir aplicativos de negócios muito poderosos.

Neste artigo vamos recordar como consumir uma APIs de terceiros em aplicativos ASP.NET Core.

Apresentando o problema

Vamos supor que você esta desenvolvendo uma aplicação que precisa saber quais os feriados municipais e nacionais para um determinado Ano, Estado e Cidade específicos.

Assim a partir da informação do ano, do estado e da cidade teremos que ter a relação dos feriados nacionais ou municipais. Felizmente existe uma API pronta que faz esse serviço neste endereço : API de Calendário e Feriados

Eu não vou entrar em detalhes da documentação que você pode consultar no link acima mas de forma bem resumida para poder acessar os feriados basta fazer uma chamada à URL, com o ano, estado e nome da cidade desejada, desta forma:

https://api.calendario.com.br/?token=[seu-token]&ano=2018&estado=SP&cidade=Sao_Paulo

Para receber os dados no formato json basta incluir o parâmetro &json=true na URL acima.

Nota: O formato para informar o nome do estado e cidades pode ser obtido neste link: http://www.calendario.com.br/api/cities.json

O retorno de uma consulta padrão com resposta no formato JSON é mostrado abaixo:

Note que é retornado as seguintes informações :

Para poder usar o serviço basta solicitar um token de acesso informando o seu email.

Então com base nisso vamos criar um pequeno projeto ASP .NET Core MVC mostrando como acessar a API e obter a lista de feriados.

O código usado neste projeto vai usar alguns dos novos recursos do C# 9 e10 como :  as instruções de alto nível , os namespaces com escopo de arquivo, o recurso Global Using. Confira nas referências os artigos que escrevi abordando estes assuntos.

recursos usados:

Criando o projeto ASP .NET Core MVC

Vamos criar um projeto ASP .NET Core MVC selecinando o template abaixo:

E vamos informar o nome FeriadosMvc para a solução e para o projeto;

A seguir vamos selecionar o framework .NET 6.0 conforme mostrado abaixo e clicar em Create.

Com o projeto ASP .NET Core MVC criado precisamos pensar em como vamos acessar a API.

Uma forma bem simples e comum de realizar esta tarefa é usar a classe HttpClient. Essa classe nos dá a capacidade de enviar solicitações HTTP para APIs de terceiros e receber respostas HTTP retornadas dessas APIs.

Cada instância de HttpClient mantém seu próprio pool de conexão que permite isolar suas solicitações de solicitações executadas por outras instâncias de HttpClient. Essa classe também atua como uma classe base para clientes HTTP mais específicos. Por exemplo, você pode criar FacebookHttpClient ou TwitterHttpClient como classes filhas de HttpClient base e pode se comunicar com APIs do Facebook e Twitter usando esses clientes HTTP específicos.

A forma recomendada de usar esta classe é criar uma instância de HttpClient e reutilizá-la durante o tempo de vida do aplicativo. Isso ocorre porque instanciar uma nova instância de HttpClient para cada solicitação pode facilmente esgotar o número de soquetes disponíveis sob cargas pesadas. Isso ocorre principalmente porque quando o objeto HttpClient é descartado, o soquete subjacente não é liberado imediatamente. Então cuidado ao usar o HttpClient !!!(Confira este post)

Definindo o modelo de domínio e configurações

Vamos iniciar criando um serviço para acessar a API e retornar os feriados com base nos critérios desejados.

Na pasta Models crie a classe FeriadoModel onde vamos definir as propriedades que desejamos obter da API com base no seu retorno:

namespace FeriadosMvc.Models;

public class FeriadoModel
{
    public string Name { get; set; }
    public string Date { get; set; }
    public string Description { get; set; }
    public string Type { get; set; }
}

No arquivo appsettings.json vamos criar a seção API onde vamos armazenar o token de acesso a API e o endereço base da URL para acessar a API:

{
  "API": {
    "token": "bWFjb3JhdIYTRREROIXNoPTU1NYTEWRTQx",
    "baseAddress": "https://api.calendario.com.br"
  },

  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Criando o serviço para obter os feriados

Crie uma pasta Services no projeto e nesta pasta crie a interface IFeriadosApiService onde vamos definir um contrato para obter os feriados a partir do ano, estado e cidade expresso na assinatura do método GetFeriados():

using FeriadosMvc.Models;
namespace FeriadosMvc.Services;

public interface IFeriadosApiService
{
    Task<List<FeriadoModel>> GetFeriados(int ano, string estado, string cidade);
}

A seguir vamos criar a classe FeriadosApiService que implementa esta interface e acessa a API:

using FeriadosMvc.Models;
using System.Text.Json;

namespace FeriadosMvc.Services;

public class FeriadosApiService : IFeriadosApiService
{
    private readonly IHttpClientFactory _clientFactory;
    private readonly IConfiguration configuration;

    public FeriadosApiService(IConfiguration config, IHttpClientFactory clientFactory)
    {
        configuration = config;
        _clientFactory = clientFactory;
    }

    public async Task<List<FeriadoModel>> GetFeriados(int ano, string estado, string cidade)
    {
        var tokenApi = configuration.GetSection("Token:TokenApi");
        var baseAddress = configuration.GetSection("Token:baseAddress");

        var client = _clientFactory.CreateClient();
        client.BaseAddress = new Uri(baseAddress.Value);

        var url = $"?ano={ano}&estado={estado}&cidade={cidade}&json=true&token={tokenApi.Value}";

        var result = new List<FeriadoModel>();

        var response = await client.GetAsync(url);

        if (response.IsSuccessStatusCode)
        {
            var stringResponse = await response.Content.ReadAsStringAsync();

            result = JsonSerializer.Deserialize<List<FeriadoModel>>
                (stringResponse,new JsonSerializerOptions()
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                });
        }
        else
        {
            throw new HttpRequestException(response.ReasonPhrase);
        }

        return result;
    }
}

Nesta classe de serviço estamos injetando no construtor os serviços de IHttpClientFactory e de IConfiguration para poder ter uma instância de HttpClient e também para poder acessar as configurações feitas no arquivo appsettings.json.

No método estamos obtendo os valores do token e do endereço de acesso a API e estamos montando a Url com os parâmetros desejados conforme a documentação da API:

var url = $"?ano={ano}&estado={estado}&cidade={cidade}&json=true&token={tokenApi.Value}";

A seguir, estamos fazendo uma chamada de API usando o método GetAsync que envia uma solicitação GET para a Uri especificada como uma operação assíncrona. O método retorna o objeto System.Net.Http.HttpResponseMessage que representa uma mensagem de resposta HTTP incluindo o código de status e os dados.

Em seguida, estamos chamando o método ReadAsStringAsync que serializa o conteúdo HTTP em uma string; e, finalmente, estamos usando JsonSerializer para desserializar a string de resposta JSON em uma lista de objetos FeriadoModel.

Registrando os serviços na classe Program

Agora precisamos registrar o serviço IFeriadosService e o serviço HttpClient em nosso projeto. Vamos fazer isso na classe Program pois não temos mais o arquivo Startup.

using FeriadosMvc.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddHttpClient();
builder.Services.AddSingleton<IFeriadosApiService, FeriadosApiService>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

Aqui poderíamos ter definido o endereço base no registro do HttpClient da seguinte forma:


 builder.Services.AddHttpClient("PublicFeriadosApi",
      c => c.BaseAddress = new Uri("https://api.calendario.com.br"));
 

E na classe FeriadosApiService  podemos injetar IHttpClientFactory e definir a instância do HttpClient:

    private readonly HttpClient client;

    public FeriadosApiService(IHttpClientFactory clientFactory)
    {
        client = clientFactory.CreateClient("PublicFeriadosApi");
    }

Não vamos fazer assim mas fica o registro desta opção.

Ajustando o controlador HomeController e usando o serviço criado

No controlador HomeController vamos substituir o código gerado por padrão pelo código abaixo:

using FeriadosMvc.Models;
using FeriadosMvc.Services;
using Microsoft.AspNetCore.Mvc;

namespace FeriadosMvc.Controllers;

public class HomeController : Controller
{
   
private readonly IFeriadosApiService _feriadosApiService;

    public HomeController(IFeriadosApiService feriadosApiService)
    {
        _feriadosApiService = feriadosApiService;
    }

    [HttpGet]
    public IActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public async Task<IActionResult> Index(int ano, string estado, string cidade)
    {
        List<FeriadoModel> feriados = new List<FeriadoModel>();

        feriados = await _feriadosApiService.GetFeriados(ano, estado, cidade);

        return View(feriados);
    }
}

 

Neste código injetamos uma instância de IFeriadosService no construtor e usamos esse serviço para invocar o método GetFeriados() de forma assíncrona.

Vamos criar a razor view Index.cshtml para permitir que o usuário informa os argumentos que serão passados para os parâmetros do método GetFeriados(ano, estado cidade).

@model List<FeriadoModel>

@{
    ViewData["Title"] = "Home Page";
}

<div>
    <h2 class="display-4">Feriados</h2>
        <form asp-controller="Home" asp-action="Index">
            <table>
                <tr>
                    <td>Ano : </td>
                    <td>
                    <select id="Ano" name="Ano">
                        <option value="2015">2015</option>
                        <option value="2016">2016</option>
                        <option value="2017">2017</option>
                        <option value="2018">2018</option>
                        <option value="2019">2019</option>
                        <option value="2020">2020</option>
                        <option selected="selected" value="2021">2021</option>
                        <option value="2022">2022</option>
                        <option value="2023">2023</option>
                        <option value="2024">2024</option>
                        <option value="2025">2025</option>
                    </select>
                    </td>
                    <td>Estado : </td>
                    <td>
                    <select id="Estado" name="Estado">
                        <option value="MG">Minas Gerais</option>
                        <option value="RS">Rio Grande do Sul</option>
                        <option value="PR">Paraná</option>
                        <option selected="selected" value="SP">São Paulo</option>
                        <option value="RJ">Rio de Janeiro</option>
                        <option value="BA">Bahia</option>
                        <option value="AM">Amazonas</option>
                    </select>
                    </td>
                    <td>Cidade : </td>
                    <td>
                    <select id="Cidade" name="Cidade">
                        <option value="BELO_HORIZONTE">Belo Horizonte</option>
                        <option value="PORTO_ALEGRE">Porto Alegre</option>
                        <option value="CURITIBA">Curitiba</option>
                        <option selected="selected" value="SAO_PAULO">São Paulo</option>
                        <option value="CAMPINAS">Campinas</option>
                        <option value="LIMEIRA">Limeira</option>
                        <option value="SANTOS">Santos</option>
                        <option value="TANABI">Tanabi</option>
                        <option value="RIO_DE_JANEIRO">Rio de Janeiro</option>
                        <option value="MANAUS">Manaus</option>
                    </select>
                    </td>
                    <td><input type="submit" value="Submeter" /></td>
                </tr>
            </table>
            <hr />
        </form>
    @if (Model != null && Model.Count > 0)
    {
        <table class="table table-bordered table-striped table-sm">
            <thead>
            <tr>
                <th>Data</th>
                <th>Nome</th>
                <th>Tipo</th>
                <th>Descricao</th>
            </tr>
            </thead>
            <tbody>
            @foreach (var item in Model)
            {
                <tr>
                    <td>@Html.DisplayFor(modelItem => item.Date)</td>
                    <td>@Html.DisplayFor(modelItem => item.Name)</td>
                    <td>@Html.DisplayFor(modelItem => item.Type)</td>
                    <td>@Html.DisplayFor(modelItem => item.Description)</td>

                </tr>
            }
            </tbody>
        </table>
    }  

</div>

Para simplificar eu criei apenas 3 tags <select> com apenas algumas opções de acesso para testarmos a aplicação.

Agora é só alegria, executando o projeto teremos o resultado abaixo:

Pegue o projeto aqui: FeriadosMvc.zip  (sem as referências)

"Eu te invoquei, ó Deus, pois me queres ouvir; inclina para mim os teus ouvidos, e escuta as minhas palavras.
Faze maravilhosas as tuas beneficências, ó tu que livras aqueles que em ti confiam dos que se levantam contra a tua destra."

Salmos 17:6,7

Referências:


José Carlos Macoratti