Ao trabalhar com uma arquitetura baseada em camadas ou Clean Architecture, um dos pontos-chave para manter a coesão e a separação de responsabilidades é entender como a camada Application se comunica com a camada API (ou Web, no caso de uma aplicação ASP.NET Core).
Neste artigo, vamos entender:
- 📐 O papel de cada camada (API x Application)
- 🧠 Como estruturar a comunicação entre elas
- 💡 Exemplos com Handlers, DTOs e MediatR
- 🧪 Boas práticas para testabilidade e desacoplamento
🏗️ Camadas da Arquitetura
┌─────────────────────┐
│ API Layer │ ← Interface HTTP (Controllers, Endpoints)
└─────────────────────┘
↓
┌─────────────────────┐
│ Application Layer │ ← Casos de Uso, DTOs, Handlers
└─────────────────────┘
↓
┌─────────────────────┐
│ Domain Layer │ ← Entidades, Regras de Negócio, Interfaces
└─────────────────────┘
↓
┌─────────────────────┐
│ Infrastructure Layer│ ← Implementações, Persistência, Serviços
└─────────────────────┘
📤 1. Quem chama quem?
A API Layer é responsável por receber requisições HTTP e converter isso em chamadas a casos de uso (Application Layer). A lógica de negócio não vive no controller — ela está encapsulada nos Handlers da Application.
📦 2. Criando um Caso de Uso (Command Handler)
// Application/Orders/Commands/CreateOrderCommand.cs
public record CreateOrderCommand(string CustomerEmail, List<string> Items) : IRequest<Guid>;
// Application/Orders/Handlers/CreateOrderHandler.cs
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, Guid>
{
public async Task<Guid> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
{
// Regras de negócio, validações, persistência via interface
var orderId = Guid.NewGuid(); // Simulação
return await Task.FromResult(orderId);
}
}
🧠 Estamos usando o MediatR para orquestrar o fluxo entre as camadas sem acoplamento direto.
🌐 3. Chamando a Application pela API
// API/Controllers/OrdersController.cs
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
private readonly IMediator _mediator;
public OrdersController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] CreateOrderCommand command)
{
var orderId = await _mediator.Send(command);
return CreatedAtAction(nameof(GetById), new { id = orderId }, orderId);
}
[HttpGet("{id}")]
public IActionResult GetById(Guid id)
{
// Aqui você pode usar outro handler/query
return Ok(new { Id = id, Status = "Mocked Order" });
}
}
🔁 4. Fluxo Resumido
[HTTP Request]
↓
[API Controller] → Recebe e valida
↓
[Mediator.Send(command)]
↓
[Application Handler]
↓
[Domain + Regras]
↓
[Interface de persistência]
📌 5. Separação de DTOs
Evite expor diretamente os modelos de domínio na API. Utilize DTOs específicos para a entrada e saída dos dados.
// API.DTOs
public record CreateOrderRequest(string CustomerEmail, List<string> Items);
[HttpPost]
public async Task<IActionResult> Create([FromBody] CreateOrderRequest request)
{
var command = new CreateOrderCommand(request.CustomerEmail, request.Items);
var orderId = await _mediator.Send(command);
return Ok(orderId);
}
🧪 6. Testabilidade e Vantagens
- ✅ Fácil de testar Handlers separadamente da API
- ✅ Sem dependência de ASP.NET Core na Application Layer
- ✅ Responsabilidade única para cada camada
- ✅ Flexível para ser usada por outras interfaces (ex: Blazor, Console, CLI)
🧭 7. Dicas de Organização
/API
└── Controllers/
└── DTOs/
└── Program.cs
/Application
└── Orders/
├── Commands/
├── Queries/
├── Handlers/
└── Validators/
/Domain
└── Entities/
└── Interfaces/
/Infrastructure
└── Persistence/
└── Services/
✅ Conclusão
A comunicação entre a API e a camada Application em .NET moderno deve ser limpa, desacoplada e testável. Utilizando MediatR, DTOs e separação de responsabilidades, você consegue:
- Aplicar Clean Architecture na prática
- Escalar sua aplicação sem dores
- Manter a legibilidade e coesão entre camadas
🤝 Conecte-se Comigo
Se você trabalha com .NET moderno e quer dominar arquitetura, C#, DevOps ou interoperabilidade, vamos conversar:
- 🌐 shifters.dev
- ✍️ Medium
- 📬 contato@dopme.io
Top comments (0)