Implementando Consultas Específicas em Web API com C# .NET

Em desenvolvimento de APIs com .NET, frequentemente precisamos implementar endpoints que vão além do básico GetAll. Este artigo explora como criar consultas específicas para recuperar elementos individuais ou filtrados através de parâmetros.

Criando um Endpoint para Consulta Específica

Para buscar um elemento específico em vez de toda a lista, podemos criar um novo endpoint que recebe parâmetros via URL:

[HttpGet("byDescription")]
public IActionResult GetByDesc(string texto)
{
    // Breakpoint para debug
    Debug.WriteLine($"Texto recebido: {texto}");

    // Lógica de filtro aqui
    var resultado = _lista.Where(x => x.Descricao.Contains(texto)).FirstOrDefault();

    if (resultado == null)
        return NotFound();

    return Ok(resultado);
}

Implementando Filtros com LINQ

O LINQ oferece uma maneira elegante e poderosa para filtrar coleções:

// Filtro por descrição contendo o texto
var pesquisado = _lista
    .Where(x => x.Descricao.Contains(texto))
    .FirstOrDefault();

// Filtro por código exato
var porCodigo = _lista
    .Where(x => x.Codigo == codigo)
    .FirstOrDefault();

// Filtro que retorna múltiplos resultados
var multiplosResultados = _lista
    .Where(x => x.Descricao.Contains(texto))
    .ToList();

Tratamento de Respostas e Códigos HTTP

É importante retornar os códigos HTTP apropriados para diferentes cenários:

[HttpGet("byId/{id}")]
public IActionResult GetById(int id)
{
    var entidade = _lista.FirstOrDefault(x => x.Id == id);

    if (entidade == null)
        return NotFound($"Nenhum registro encontrado com ID {id}");

    return Ok(entidade);
}

[HttpGet("byDescription")]
public IActionResult GetByDescription(string descricao)
{
    if (string.IsNullOrEmpty(descricao))
        return BadRequest("Parâmetro 'descricao' é obrigatório");

    var resultados = _lista
        .Where(x => x.Descricao.Contains(descricao, StringComparison.OrdinalIgnoreCase))
        .ToList();

    if (!resultados.Any())
        return NotFound($"Nenhum registro encontrado com a descrição '{descricao}'");

    return Ok(resultados);
}

Considerações sobre Performance

Ao trabalhar com grandes volumes de dados, é importante considerar a eficiência das consultas:

// Uso de AsQueryable para eficiência em grandes datasets
[HttpGet("filtered")]
public IActionResult GetFiltered([FromQuery] string filtro, [FromQuery] int pagina = 1, [FromQuery] int tamanhoPagina = 20)
{
    var query = _context.Entidades.AsQueryable();

    if (!string.IsNullOrEmpty(filtro))
    {
        query = query.Where(x => x.Descricao.Contains(filtro));
    }

    var resultados = query
        .Skip((pagina - 1) * tamanhoPagina)
        .Take(tamanhoPagina)
        .ToList();

    return Ok(new {
        Pagina = pagina,
        TamanhoPagina = tamanhoPagina,
        Total = query.Count(),
        Resultados = resultados
    });
}

Validação de Parâmetros

A validação adequada dos parâmetros é essencial para uma API robusta:

[HttpGet("search")]
public IActionResult Search([FromQuery] SearchRequest request)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);

    if (request.PageSize > 100)
        return BadRequest("O tamanho máximo da página é 100");

    // Lógica de busca aqui
    return Ok();
}

public class SearchRequest
{
    [Required]
    [MinLength(2)]
    public string Termo { get; set; }

    [Range(1, 100)]
    public int PageSize { get; set; } = 20;

    [Range(1, int.MaxValue)]
    public int Page { get; set; } = 1;
}

Conclusão

A implementação de endpoints específicos para consultas filtradas é uma prática essencial no desenvolvimento de APIs RESTful. Utilizando os recursos do LINQ para filtros e o sistema de rotas do ASP.NET Core, podemos criar APIs flexíveis e eficientes.

Lembre-se de sempre:

  • Validar parâmetros de entrada
  • Retornar códigos HTTP apropriados
  • Considerar performance em grandes volumes de dados
  • Documentar os endpoints usando ferramentas como Swagger
  • Implementar tratamento de erros consistente

Essas práticas garantem que sua API seja robusta, fácil de usar e mantenha boa performance mesmo com o crescimento do volume de dados.