ASP .NET Core -  Três maneiras de retornar dados de uma Web API


Neste artigo veremos as 3 formas mais comuns de retornar dados a partir de uma Web API.

API é o acrônimo de Application Programming Interface ou, Interface de Programação de Aplicativos que é um conjunto de padrões de programação que permite a construção de aplicativos e a sua integração e comunicação com outros programas.

O ASP.NET Core permite que você crie serviços RESTful usando a Web API. Normalmente, você deseja retornar dados e códigos de status HTTP de um controlador da API. Atualmente existem três maneiras de retornar valores de um controlador de uma API.

Para este artigo estamos usando uma Web API chamada ProdutosController criada na ASP .NET Core 2.2 que permitindo aos seus clientes:

A API foi criada usando os recursos do EF Core 2.2 e usa um modelo de domínio (amênico) Produto:

public class Produto
{
    public int Id { get; set; }
    public string Nome { get; set; }
    public int Estoque { get; set; }
    public decimal Preco { get; set; }
}

Vejamos agora quais as 3 formas de retornar dados desta API.

Recursos Usados:

1- Retornando um tipo específico

A forma mais simples e direta de retornar valores de uma API é retornar um tipo específico. Considere o código abaixo que retorna uma lista de produtos:

        [HttpGet]
        public List<Produto> Get()
        {
          return _context.Produtos.ToList();
        }

Neste exemplo, a Action Get() retorna um tipo conhecido, ou seja, uma lista de objetos Produto.

Essa abordagem é adequada se você simplesmente deseja retornar dados para o cliente sem considerar condições inesperadas, como exceções e códigos HTTP, como 404 e 200.

Outro exemplo usando métodos assíncronos que retorna uma lista de objetos Produto:

        [HttpGet]
        public async Task<ActionResult<IEnumerable<Produto>>> GetProdutos()
        {
           return await _context.Produtos.ToListAsync();
        }

2- Retornando IActionResult

Agora quando o seu valor de retorno for uma mistura de dados e códigos HTTP, você não pode usar a abordagem anterior. Assim se  você deseja retornar NotFoundResult ou OkResult ou ObjectResult, não poderá usar a abordagem anterior.

Nesse caso, você pode retornar os valores como IActionResult. Considere o seguinte exemplo:

	[HttpGet("{id}")]
	public IActionResult Get(string id)
	{
	    Produto prod = db.Produtos.Find(id);
	    if (prod == null)
	    {
	        return NotFound();
	    }
	    return Ok(prod);
	}

Nesse caso, queremos retornar um produto específico com base no Id passado na Action. É possível que o Id seja inválido e Find() pode falhar ao retornar um objeto Produto. Se Find() retornar null, queremos retornar a resposta 404 - Not Found ao cliente.

Por outro lado, se o Produto for encontrado, queremos retornar 200 - Ok para o cliente, juntamente com o objeto Produto encontrado.

Isso pode ser feito assim que definirmos o tipo de retorno de IActionResult. A interface IActionResult é implementada por classes como NotFoundResult e OkResult. Os métodos NotFound() e Ok() retornam esses objetos para o cliente.

Nesse contexto esse é o tipo adequado de retorno a ser usado.

Considere agora a seguinte Action assíncrona onde temos duas possibilidades de tipos de retornos:

[HttpPost]
[ProducesResponseType(typeof(Product), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateAsync([FromBody] Produto produto)
{
    if (produto.Description.Contains("XYZ"))
    {
        return BadRequest();
    }

    await _repository.AddProdutoAsync(produto);

    return CreatedAtAction(nameof(GetById), new { id = produto.Id }, produto);
}

Neste código temos que :

  1. Um código de status 400 (BadRequest) é retornado pelo runtime da ASP.NET Core quando a descrição do produto contiver "XYZ".
     
  2. Um código de status 201 é gerado pelo método CreatedAtAction quando um produto é criado. Nesse código, o objeto Produto é retornado.
3- Retornando ActionResult<T>

Um dos novos recursos do ASP.NET Core 2.1 é, um novo tipo chamado ActionResult<T>, que permite que você retorne o tipo do response ou qualquer resultado da Action, enquanto ainda indica o tipo do response.

Assim, o ActionResult<T> permite combinar as duas abordagens discutidas anteriormente. Você pode retornar um tipo derivado de ActionResult ou um tipo específico. Considere o exemplo a seguir usando a Action Get():

           [HttpGet("{id}")]
	public ActionResult<Produto> Get(string id)
	{	
	      Produto prod = _context.Produtos.Find(id);
	      if (prod == null)
                 {
		return NotFound();
                 }		
                return prod;
	}

Como você pode ver, não é necessário envolver o objeto prod em Ok() ou ObjectResult. Você pode retornar NotFoundResult ou ActionResult<Produto>.

Como a linguagem C# não suporta a conversão implicita de operadores em interfaces. para usar o recurso acima temos que converter a interface para um tipo concreto.

No exemplo de código a seguir o uso de IEnumerable não funciona:

[HttpGet]
public ActionResult<IEnumerable<Produto>> Get()
{
    return _repository.GetProdutos();
}

Uma opção para corrigir o problema é retornar :  _repository.GetProdutos().ToList();

Essas são as 3 formas básicas atuais de retornar dados de uma API.

"Não quero, porém, irmãos, que sejais ignorantes acerca dos que já dormem, para que não vos entristeçais, como os demais, que não têm esperança.
Porque, se cremos que Jesus morreu e ressuscitou, assim também aos que em Jesus dormem, Deus os tornará a trazer com ele."

1 Tessalonicenses 4:13,14

Referências:


José Carlos Macoratti