DEV Community

Yuri Peixinho
Yuri Peixinho

Posted on

Onion Architecture (Arquitetura Cebola)

Introdução

Seu principal objetivo é enfrentar os desafios encontrados na arquitetura em camadas e fornecer soluções para problemas comuns como aclopamento, separação das responsabilidades, colocando a regra de negócio no centro do sistema, isolando-as de detalhes como (banco de dados, interface, frameworks, etc.).

Descomplicando a Arquitetura

Na arquitetura em camadas tradicional, o fluxo de dependência é costuma a ser de fora pra dentro: a camada de interface (UI) interage com a lógica de negócio, que por sua vez depende da camada de dados. Esse modelo cria acoplamento direto entre as camadas, dificultando a substituição de tecnologias ou a realização de testes isolados.

A Onion Architecture propõe o inverso dessa lógica. Em vez de organizar o sistema a partir das camadas externas, ela o estrutura de dentro pra fora, tendo núcleo do domínio como centro.

As camadas internas contêm as regras de negócios puras e não conhecem nada sobre a infraestrutura ou interface. Já as camadas mais externas dependem das internas, atuando apenas como meios de entrada (UI, APIs) ou implementação de detalhes como banco de dados e/ou serviços externos.

Destrinchando as camadas

1. Camada de domínio (Domain Model)

Representa os objetos de negócios e o comportamento, e, pode conter interfaces de domínio.

  • Essa camada não possui nenhuma dependência

2. Camada de serviço do Domínio (Domain Services)

Cria a abstração entre as entidades do domínio e a lógica dos negócios do aplicativo. Nesta camada, temos as interfaces que fornecem o comportamento de salvar e recuperar objetos, geralmente envolvendo um repositório que acessa a fonte de dados

4. Camada de serviço da Aplicação (Application Services)

A camada da aplicação que mantém interfaces com operaçÕes comuns como adicionar, salvar, editar e excluir. Além disso, essa camada é usada pra se comunicar com a camada de interface do usuário e da camada do repositório.

  • É nessa camada que acessamos o “miolo” do projeto.

5. Camada externas (UI, Infrastructure, tests)

É o anel mais externo da arquitetura. Nele temos os componentes que mudam com frequência: a camada de apresentação, o acesso aos dados e os testes

Exemplo de Projeto

Example/ │ ├── Core/ │ ├── Domain/ │ │ ├── Entities/ │ │ │ ├── UserEntity.cs │ │ │ └── GroupEntity.cs │ │ ├── Dependencies/ │ │ └── Exceptions/ ← (opcional) │ │ │ ├── DomainServices/ │ │ ├── Repositories/ │ │ │ ├── IUserRepository.cs │ │ │ └── IGroupRepository.cs │ │ ├── Dependencies/ │ │ └── Validators/ ← (opcional) │ │ │ └── Application/ │ ├── Services/ │ │ ├── IUserService.cs │ │ ├── IGroupService.cs │ │ ├── UserService.cs │ │ └── GroupService.cs │ ├── DTOs/ ← (opcional) │ ├── Mappers/ ← (opcional) │ └── Dependencies/ │ ├── Infrastructure/ │ ├── Repositories/ │ │ ├── UserRepository.cs │ │ └── GroupRepository.cs │ ├── Data/ │ │ ├── AppDbContext.cs │ │ └── Configurations/ │ ├── Dependencies/ │ └── Migrations/ ← (caso use EF Core) │ └── WebApi/ ├── Controllers/ │ ├── UserController.cs │ └── GroupController.cs ├── Program.cs ├── Startup.cs └── appsettings.json 
Enter fullscreen mode Exit fullscreen mode
Camada da Cebola Pasta no projeto Responsabilidade principal
Domain Example.Core.Domain Entidades e regras de negócio puras
Domain Services Example.Core.DomainServices Interfaces de repositórios e regras de domínio mais complexas
Application Example.Core.Application Casos de uso, orquestração e serviços de aplicação
Infrastructure Example.Infrastructure Implementações concretas (banco, API externa etc.)
UI / API Example.WebApi Ponto de entrada da aplicação (controladores REST, endpoints)

Exemplo simples: “Cadastrar Usuário”

Parafraseando o ChatGPT temos o seguinte cenário:

1️⃣ Camada mais externa – WebAPI (Interface / Delivery Layer)

É o ponto de entrada — recebe a requisição HTTP.

// Example.WebApi.Controllers/UserController.cs [ApiController] [Route("api/users")] public class UserController : ControllerBase { private readonly IUserService _userService; public UserController(IUserService userService) { _userService = userService; } [HttpPost] public IActionResult Create(UserDto user) { _userService.CreateUser(user); return Ok(); } } 
Enter fullscreen mode Exit fullscreen mode

📤 Fluxo:

➡️ WebApi chama Application

A API não conhece o domínio nem o banco — só o serviço da aplicação.


2️⃣ Camada de Aplicação (Application Layer)

Contém regras de orquestração, casos de uso, DTOs e interfaces de serviço.

// Example.Core.Application.Services/UserService.cs public class UserService : IUserService { private readonly IUserRepository _userRepository; private readonly IPasswordHasher _passwordHasher; public UserService(IUserRepository userRepository, IPasswordHasher passwordHasher) { _userRepository = userRepository; _passwordHasher = passwordHasher; } public void CreateUser(UserDto user) { var entity = new UserEntity(user.Name, _passwordHasher.Hash(user.Password)); _userRepository.Save(entity); } } 
Enter fullscreen mode Exit fullscreen mode

📤 Fluxo:

➡️ Application chama Domain (para criar entidades)

➡️ Application chama Infrastructure (através da interface IUserRepository)


3️⃣ Camada de Domínio (Domain Layer)

É o núcleo da cebola, contendo regras de negócio puras, entidades e interfaces.

// Example.Core.Domain/Entities/UserEntity.cs public class UserEntity { public string Name { get; } public string PasswordHash { get; } public UserEntity(string name, string passwordHash) { if (string.IsNullOrEmpty(name)) throw new ArgumentException("Nome é obrigatório"); Name = name; PasswordHash = passwordHash; } } 
Enter fullscreen mode Exit fullscreen mode

📤 Fluxo:

➡️ Domain é chamado por Application, mas não depende de ninguém.


4️⃣ Camada de Infraestrutura (Infrastructure Layer)

Implementa interfaces definidas no domínio — banco, APIs externas, etc.

// Example.Infrastructure.Repositories/UserRepository.cs public class UserRepository : IUserRepository { private readonly AppDbContext _context; public UserRepository(AppDbContext context) { _context = context; } public void Save(UserEntity user) { _context.Users.Add(user); _context.SaveChanges(); } } 
Enter fullscreen mode Exit fullscreen mode

📤 Fluxo:

➡️ Infrastructure é chamada por Application, mas depende do Domain (pelas interfaces e entidades).


🔁 Fluxo geral do “Cadastrar Usuário”:

Ordem Ação De Para
1 Requisição HTTP POST 🧩 WebApi Application
2 Executa caso de uso Application Domain (cria UserEntity)
3 Persiste usuário Application Infrastructure (UserRepository)
4 Repositório salva no banco Infrastructure Banco de dados

Top comments (0)