Com a diversificação do acesso, está se tornando um padrão a criação de back-end, APIs, que posteriormente serão consumidas por outras aplicações. Por isso, atualmente é imprescindível saber realizar este procedimento. Felizmente, no C#, a biblioteca Flurl facilita, e muito, este processo.
Flurl
Criada por Todd Menier, Flurl é uma biblioteca open source para .NET. Ela se define como um builder de URL, moderno, assíncrono, fluent, portável, testável, entre outras buzzword e uma biblioteca de requisições HTTP.
De forma simples, ela nos permite criar requisições HTTP que são facilmente testáveis. Entretanto, não abordaremos este detalhe aqui. Neste arquivo, veremos apenas a criação de requisições.
Curso C# (C Sharp) Intermediário
Conhecer o cursoAplicação base
Para exemplificar o uso da biblioteca, irei utilizar como base a aplicação demonstrada no artigo da biblioteca RepoDB e o pacote Tw Dev Server do Akira Hanashiro.
Consumindo dados da API
No momento, ao executar a aplicação, os produtos são listados do banco:
Iremos alterá-la pra que esses dados sejam obtidos pela API.
Por esta aplicação adotar o padrão repository, as principais alterações serão realizadas nesta camada. As demais sofrerão apenas adaptações pontuais.
A primeira coisa à ser feita é adicionar a biblioteca Flurl:
dotnet add package Flurl.Http
Por ser uma biblioteca fluent, seus métodos são de extensão. Assim, inicialmente iremos definir a url:
const string url = "http://localhost:3002/api/products";
Em seguida iremos alterar o método FindAll
, que no momento tem o conteúdo abaixo:
public IEnumerable<Product> FindAll()
{
return QueryAll();
}
A obtenção de dados é feita através de uma requisição GET. Como os dados da nossa API são retornados como JSON, a Flurl possui o método de extensão GetJsonAsync
que já cria esta requisição e parseia os dados:
public async Task<IEnumerable<Product>> FindAll()
{
return await url.GetJsonAsync<List<Product>>();
}
Como GetJsonAsync
é assíncrono, note que foi necessário definir o FindAll()
como assíncrono. Com isso, será necessário modificar a interface:
Task<IEnumerable<T>> FindAll();
E o controller:
public async Task<ActionResult> Index()
{
return View((await productRepository.FindAll()).ToList());
}
Também será necessário modificar o model, porque os ids criados pela API são GUID:
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public double Price { get; set; }
}
Como a API não possui nenhum dado, por enquanto a listagem não mostra nada:
Enviando dados para a API
Com a listagem pronta, vamos enviar dados para a API. Isso é feito via uma requisição POST. Assim, como a GET, a biblioteca possui o método de extensão PostJsonAsync
que já facilita a criação desta requisição:
public async Task Add(Product item)
{
await url.PostJsonAsync(item);
}
Também é necessário modificar a interface:
Task Add(T item);
E o controller:
public async Task<ActionResult> Create([Bind("Id,Name,Quantity,Price")] Product product)
{
if (ModelState.IsValid)
{
await productRepository.Add(product);
return RedirectToAction("Index");
}
return View(product);
}
Agora podemos adicionar dados na API e consumi-los:
Atualizando dados da API
O processo de atualização ocorre em duas etapas. Inicialmente é necessário obter os dados do registro que será atualizado. Para isso, deve ser feita uma requisição GET, passando o id do registro:
public async Task<Product> FindByID(string id)
{
return await url
.SetQueryParams(new { id = id })
.GetJsonAsync<Product>();
}
Note que estamos utilizando o método SetQueryParams
passar o id via querystring. No final, teremos uma URL no seguinte formato: http://localhost:3002/api/products?id=<valor id>
.
Assim como antes, também é necessário mudar a interface:
Task<T> FindByID(string id);
E o controller:
public async Task<ActionResult> Edit(string id)
{
if (id == null)
{
return StatusCode(StatusCodes.Status400BadRequest);
}
Product product = await productRepository.FindByID(id);
if (product == null)
{
return StatusCode(StatusCodes.Status404NotFound);
}
return View(product);
}
Aproveite e altere o método de detalhes:
public async Task<ActionResult> Details(string id)
{
if (id == null)
{
return StatusCode(StatusCodes.Status404NotFound);
}
Product product = await productRepository.FindByID(id);
if (product == null)
{
return StatusCode(StatusCodes.Status404NotFound);
}
return View(product);
}
Agora ao clicar no link de edição (ou detalhes), os dados do produto serão mostrados:
A atualização dos dados é realizada via uma requisição PUT e como deve imaginar, a Flurl também fornece um método de extensão que facilita a implementação desta requisição:
public async Task Update(Product item)
{
await url
.SetQueryParams(new { id = item.Id })
.PutJsonAsync(item);
}
Note que também é necessário passar o ID via querystring, pois esta é uma especificação da API.
Não se esqueça de mudar a interface:
Task Update(T item);
E o controller:
public async Task<ActionResult> Edit([Bind("Id,Name,Quantity,Price")] Product product)
{
if (ModelState.IsValid)
{
await productRepository.Update(product);
return RedirectToAction("Index");
}
return View(product);
}
Agora, poderemos alterar os nossos registros:
Excluindo dados da API
Para finalizar, falta implementar apenas a exclusão dos dados. Isso é feito via uma requisição DELETE, que pode ser implementada via o método de extensão DeleteAsync
:
public async Task Remove(string id)
{
await url
.SetQueryParams(new { id = id })
.DeleteAsync();
}
Não se esqueça que é necessário alterar a interface:
Task Remove(string id);
E o controller:
public async Task<ActionResult> DeleteConfirmed(string id)
{
await productRepository.Remove(id);
return RedirectToAction("Index");
}
Ao remover o único registro da nossa lista, ela voltará a ficar vazia:
Curso C# - Orientação a Objetos
Conhecer o cursoConclusão
Note que com poucas alterações, conseguimos alterar a fonte de dados da aplicação para uma API. E esta comunicação com a API foi facilitada graças a biblioteca Flurl.
Esta biblioteca fornece uma grande gama de recursos e opções que conheceremos em artigos futuros. Entretanto, caso necessite trabalhar com API no .NET, não deixe de dar uma olhada na sua documentação. Tenho certeza que ela irá facilitar, e muito, o seu trabalho.