Retornando recursos do banco
ResumoLigamos o controller à Service Layer para buscar categorias reais do banco e retorná-las com os status codes HTTP apropriados.
1. Objetivos de Aprendizagem#
- Injetar a Service Layer no controller.
- Retornar coleções e recursos únicos com
Ok,NotFound. - Usar
IServiceManagerpara orquestrar a busca.
2. Pré-requisitos#
- Controllers e roteamento (tópico 18.1).
3. Conceito#
O controller não acessa o DbContext diretamente: ele chama a Service Layer, que usa o IRepositoryManager. Isso preserva a separação de camadas do Onion. Retornamos IActionResult para escolher o status code correto: 200 OK com corpo, 404 Not Found quando o recurso não existe.
4. Mão na Massa#
4.1. Setup#
Assuma um IServiceManager (análogo ao IRepositoryManager) já registrado como Scoped.
4.2. Implementação Passo a Passo#
- Serviço:
public interface ICategoriaService
{
Task<IEnumerable<Categoria>> GetAllAsync(bool trackChanges);
}
public class CategoriaService : ICategoriaService
{
private readonly IRepositoryManager _repo;
public CategoriaService(IRepositoryManager repo) => _repo = repo;
public async Task<IEnumerable<Categoria>> GetAllAsync(bool trackChanges) =>
await _repo.Categoria.GetAllAsync(trackChanges);
}
- Controller consumindo o serviço:
[HttpGet]
public async Task<IActionResult> GetCategorias()
{
var categorias = await _service.Categoria.GetAllAsync(trackChanges: false);
return Ok(categorias);
}
4.3. Executando#
dotnet run
curl http://localhost:5000/api/categorias
Retorna 200 OK com a lista em JSON.
5. Exemplo Completo#
[ApiController]
[Route("api/categorias")]
public class CategoriasController : ControllerBase
{
private readonly IServiceManager _service;
public CategoriasController(IServiceManager service) => _service = service;
[HttpGet]
public async Task<IActionResult> GetCategorias()
{
var categorias = await _service.Categoria.GetAllAsync(trackChanges: false);
return Ok(categorias);
}
}
6. Boas Práticas e Armadilhas#
| Faça | Evite |
|---|---|
Usar trackChanges: false em leituras | Rastrear entidades desnecessariamente |
| Retornar status codes semânticos | Retornar sempre 200, mesmo em erro |
| Manter o controller fino, delegando ao serviço | Lógica de negócio dentro da ação |
Atençãoretornar a entidade diretamente vaza o modelo de domínio para o cliente (e pode causar loops de serialização em relacionamentos). No próximo tópico introduzimos DTOs para resolver isso.
7. Segurança e Produção#
- Expor entidades cruas pode revelar campos internos (ex.: flags, chaves). Sempre projete para DTOs em endpoints públicos.
- Consultas de leitura devem ser paginadas em coleções grandes (Módulo 30) para evitar respostas gigantes.
8. Exercícios#
- Fácil: adicione
GET /api/produtosretornando todos os produtos. - Médio: trate o caso de coleção vazia retornando
200com lista vazia (não404). - Desafio: meça o tempo de resposta com e sem
AsNoTrackingem uma tabela grande.
9. Resumo#
O controller delega à Service Layer, que usa o repositório para buscar dados. Retornamos status codes semânticos e identificamos o problema de expor entidades diretamente.
10. Próximos Passos#
Introduzimos DTOs e AutoMapper para desacoplar o contrato da API do modelo de domínio.
11. Referências#
- Microsoft Learn — Tipos de retorno de ações de API
- Microsoft Learn — Injeção de dependência
- Microsoft Learn — Consultas com EF Core