12 de Junho de 2025
APIs e serviços com fronteiras claras
Como desenhar fronteiras entre rotas, serviços e responsabilidades sem transformar o sistema num monte de acoplamento escondido.
Andrews Ribeiro
Founder & Engineer
5 min Intermediario Sistemas
Trilha
Trilha de system design para entrevistas
Etapa 4 / 19
O problema
Muita API fica confusa não porque faltou framework, mas porque faltou combinado sobre responsabilidade.
Ai aparece o tipo de código que todo mundo reconhece:
- controller valida formato, faz regra, consulta banco e devolve resposta
- service conhece
req,res, status code e cabecalho - repository decide desconto, status inicial e regra de negócio
- helper solto faz metade do fluxo e ninguém sabe se pode mexer
Enquanto o fluxo esta pequeno, isso parece só “jeito do projeto”. O problema aparece quando a regra muda, quando entra outro canal alem do HTTP ou quando o time precisa depurar um incidente. Nessa hora, a pergunta vira: onde essa decisão deveria morar?
Modelo mental
Fronteira boa e a que reduz dúvida.
Quando alguém abre o código, deveria ficar fácil responder:
- quem recebe input externo
- quem valida formato, permissao e contrato
- quem toma a decisão de negócio
- quem fala com banco, fila ou provider
- quem traduz o resultado para o formato da API
Você não precisa de arquitetura cerimonial para isso. Precisa separar quatro tipos de responsabilidade que costumam se misturar:
- Transporte: HTTP, fila, RPC, status code, serialização.
- Regra de negócio: decisão sobre o que pode ou não pode acontecer.
- Infraestrutura: banco, cache, provider externo, fila.
- Apresentacao do resultado: formato da resposta, mensagem, payload.
Uma regra prática ajuda muito:
se o mesmo arquivo decide regra de negócio e ao mesmo tempo conhece detalhe de HTTP ou persistencia, a fronteira já começou a borrar.
Quebrando o problema
Uma divisao simples, que funciona em bastante sistema real, costuma ser esta:
- A rota recebe o request, valida o básico, autentica e chama um fluxo.
- O service ou use case concentra a regra e orquestra o caminho feliz e o caminho de erro.
- Repository, client ou gateway falam com banco, fila e serviço externo.
- A camada de entrada traduz o resultado para a resposta da API.
Isso não e religiao. E só uma forma de impedir um arquivo central que faz tudo.
Outra pergunta boa e esta:
se a regra de negócio mudar amanha, onde eu espero mexer primeiro?
Se a resposta honesta for “talvez em tres controllers, dois helpers e um repository”, a fronteira esta ruim.
Heuristicas que funcionam bem
Tem alguns sinais bem práticos de fronteira borrada:
- se para testar a regra de negócio você precisa mockar
reqoures, a regra esta presa no lugar errado - se o service devolve
status: 409ou mensagem HTTP, ele esta sabendo demais sobre transporte - se o repository decide “pedido nasce como pending ou approved”, ele esta carregando regra demais
- se a rota conhece SQL, timeout de provider e fallback de cache, ela virou centro de comando
O oposto também e verdade. Fronteira melhor costuma produzir um efeito bom:
- da para mudar a regra sem reabrir a camada HTTP inteira
- da para trocar provider sem reescrever decisão de negócio
- da para reusar o mesmo fluxo em API, worker e job interno
Exemplo simples
Imagina um endpoint de criação de pedido.
Numa versão confusa, o controller faz tudo:
- valida carrinho
- checa estoque
- calcula frete
- define status inicial
- salva no banco
- manda email
Funciona até o dia em que:
- o frete muda
- a confirmação passa a sair por evento
- o mesmo fluxo precisa rodar num worker de reprocessamento
Agora pensa na mesma operação com fronteira melhor:
- a rota valida input, autenticação e contrato
- o service
createOrderdecide estoque, total, frete, status inicial e efeitos necessários - o repository persiste pedido e itens
- um client fala com provider de pagamento
- um evento ou fila dispara notificação depois da confirmação
O ganho não e estetico. E operacional.
Se a regra de frete mudar, você já sabe onde ir. Se trocar banco, a regra principal não precisa aprender SQL novo. Se email falhar, o controller não precisa virar um bloco de try/catch que sabe tudo sobre o fluxo.
Onde muita gente erra
- espalhar regra de negócio entre várias camadas sem critério
- criar camada demais sem responsabilidade distinta
- acoplar o formato da API ao formato interno da tabela
- fazer controller virar service com nome diferente
- discutir arquitetura como estrutura de pasta em vez de responsabilidade
Também existe o erro contrario: exagerar na separação.
Tem endpoint simples que não precisa de cinco objetos, tres interfaces e dois factories. Se a operação e trivial e a chance de reuso e baixa, simplificar pode ser a melhor escolha. O ponto não e multiplicar arquivos. E evitar mistura perigosa.
Como um senior pensa
Quem tem mais experiência costuma olhar primeiro para manutenção e mudança, não para pureza arquitetural.
O raciocínio geralmente e este:
“Eu quero que a regra importante fique num lugar previsivel. E quero que detalhes de HTTP, banco e provider não vazem para onde a decisão mora.”
Isso ajuda em tres frentes ao mesmo tempo:
- diminui efeito cascata quando a regra muda
- facilita teste no nivel certo
- deixa mais fácil reaproveitar o mesmo fluxo fora da API
Em trabalho real, isso vale mais do que o diagrama bonito. Em entrevista, mostra que você não esta recitando padrão. Esta tentando diminuir custo de manutenção.
O que o entrevistador quer ver
Quando o assunto e fronteira entre API e serviço, o entrevistador normalmente quer perceber se você:
- separa responsabilidade com critério
- sabe onde a regra de negócio deve morar
- evita acoplamento entre HTTP, regra e persistencia
- pensa em mudança futura, não só em primeira entrega
Uma resposta forte costuma soar assim:
“Controller recebe e valida o request. A regra principal fica no fluxo de negócio. Banco e provider ficam atras de uma camada que eu consigo trocar sem mover a decisão principal.”
Isso passa uma mensagem boa: você pensa em fronteira para diminuir risco, não para parecer sofisticado.
API boa não e a que tem mais camada. E a que deixa obvio onde cada decisão mora.
Resumo rápido
O que vale manter na cabeça
- Fronteira boa não e sobre pasta bonita. E sobre deixar claro onde a regra de negócio mora.
- Controller que decide regra, repository que toma decisão e service que fala HTTP costumam ser sinais de fronteira borrada.
- O desenho certo e o que faz a mudança obvia: se a regra mudar, você sabe onde mexer primeiro.
- Camada demais também atrapalha. O objetivo e separar responsabilidade, não colecionar nomes.
Checklist de pratica
Use isto ao responder
- Consigo apontar onde termina validação de transporte e começa regra de negócio em um endpoint real?
- Sei dizer que tipo de coisa deve morar no controller, no service e no repository?
- Consigo identificar um arquivo que mistura HTTP, regra e persistencia ao mesmo tempo?
- Se a regra do fluxo mudar amanha, eu sei onde esperaria mexer primeiro?
Você concluiu este artigo
Parte da trilha: Trilha de system design para entrevistas (4/19)
Compartilhar esta página
Copie o link manualmente no campo abaixo.