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)