Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Arquitetura Hexagonal no Node.js: portas e adapters

Atualizado em: 13 de outubro de 2026

Estação de trabalho usada no desenvolvimento de aplicações Node.js

Arquitetura Hexagonal no Node.js, também chamada de Ports and Adapters, organiza a aplicação ao redor das regras de negócio. Entradas como HTTP, fila e CLI usam portas para chamar o núcleo. Saídas como banco, cache e serviços externos implementam portas exigidas pelo núcleo.

O objetivo é impedir que framework e infraestrutura definam a estrutura do sistema. A aplicação pode ser testada sem servidor real e pode trocar adapters sem reescrever casos de uso.

Neste guia, você aprenderá portas de entrada e saída, adapters, composição, testes, eventos e boas práticas.

O hexágono

O desenho em hexágono não indica seis camadas. Ele representa várias formas de interação com o mesmo núcleo:

  • HTTP;
  • GraphQL;
  • CLI;
  • fila;
  • cron;
  • testes;
  • banco;
  • serviço externo.

Portas de entrada

Uma porta de entrada representa uma capacidade da aplicação:

export function criarRegistrarPagamento({ payments, gateway, clock }) {
  return async function registrar(input) {
    const result = await gateway.cobrar(input.amount);
    const payment = {
      id: result.id,
      amount: input.amount,
      status: result.status,
      createdAt: clock.now()
    };
    await payments.salvar(payment);
    return payment;
  };
}

HTTP e fila podem chamar a mesma função.

Adapter HTTP

export function criarPaymentController(registerPayment) {
  return async function controller(req, res) {
    const payment = await registerPayment({
      amount: req.body.amount
    });
    res.status(201).json(payment);
  };
}

O adapter traduz protocolo para input do caso de uso.

Adapter de fila

export function criarPaymentConsumer(registerPayment) {
  return async function consume(message) {
    await registerPayment({ amount: message.amount });
  };
}

A regra não é duplicada.

Portas de saída

O caso de uso exige capacidades externas:

  • salvar pagamento;
  • cobrar gateway;
  • obter horário;
  • publicar evento;
  • registrar auditoria.

Essas portas são implementadas por adapters.

Adapter PostgreSQL

export function criarPaymentRepository(pool) {
  return {
    async salvar(payment) {
      await pool.query(
        `INSERT INTO payments (id, amount, status, created_at)
         VALUES ($1, $2, $3, $4)`,
        [payment.id, payment.amount, payment.status, payment.createdAt]
      );
    }
  };
}

Adapter de gateway

export function criarGatewayAdapter(client) {
  return {
    async cobrar(amount) {
      const response = await client.post('/charges', { amount });
      return { id: response.id, status: response.status };
    }
  };
}

Timeout, retry e circuit breaker ficam no adapter ou em decorators de infraestrutura.

Composition root

const pool = criarPool(config.databaseUrl);
const repository = criarPaymentRepository(pool);
const gateway = criarGatewayAdapter(httpClient);
const registerPayment = criarRegistrarPagamento({
  payments: repository,
  gateway,
  clock: systemClock
});
const app = criarHttpApp({ registerPayment });

Veja Dependency Injection no Node.js.

Estrutura de pastas

src/
  core/
    payment.js
    register-payment.js
    ports/
  adapters/
    http/
    postgres/
    payment-gateway/
    messaging/
  main.js

Não existe pasta obrigatória. O teste real é observar a direção dos imports.

Diferença para camadas tradicionais

Em uma arquitetura em camadas, o fluxo costuma ser controller → service → repository. Na hexagonal, o foco é distinguir núcleo, portas e adapters. Os conceitos podem coexistir.

Relação com Clean Architecture

As duas abordagens defendem dependências apontando para dentro. A Clean Architecture detalha camadas e políticas; a hexagonal enfatiza portas e adapters.

Consulte Clean Architecture no Node.js.

Repository como adapter

Um repository implementa uma porta de persistência. Veja Repository Pattern no Node.js.

Service Layer como porta de entrada

Um método de aplicação pode ser a porta usada por controllers e consumers. Consulte Service Layer no Node.js.

Testes do núcleo

const payments = criarPaymentRepositoryFake();
const gateway = {
  async cobrar() {
    return { id: 'p-1', status: 'approved' };
  }
};

const register = criarRegistrarPagamento({ payments, gateway, clock });
const result = await register({ amount: 100 });
assert.equal(result.status, 'approved');

Nenhum servidor ou banco é necessário.

Testes de adapters

Adapters precisam de testes próprios:

  • controller: status, headers e serialização;
  • repository: query, tipos e transação;
  • gateway: request, timeout e erros;
  • consumer: ack, retry e idempotência.

Adapters substituíveis

Durante desenvolvimento, uma porta pode usar memória. Em produção, PostgreSQL. A troca não deve exigir alteração do caso de uso.

Eventos

Publicação de eventos é uma porta de saída. O núcleo cria o fato; um adapter decide como persistir ou enviar.

Autorização

A regra de autorização pode fazer parte do caso de uso quando depende do negócio. Validação de token e extração de identidade pertencem ao adapter de entrada.

Erros

O núcleo lança erros próprios. Adapters traduzem para HTTP, nack, exit code ou mensagem de CLI.

Observabilidade

Logs e métricas podem ser portas ou decorators. Evite contaminar entidades com chamadas diretas ao SDK de observabilidade.

Quando usar

A arquitetura é útil quando:

  • há múltiplas entradas;
  • integrações mudam;
  • regras de negócio são importantes;
  • testes rápidos são necessários;
  • equipes trabalham em adapters diferentes.

Quando simplificar

Um script pequeno ou CRUD básico pode usar módulos diretos. Criar dezenas de interfaces sem variação real aumenta custo.

Erros comuns

  • chamar qualquer arquivo de porta;
  • núcleo importando framework;
  • adapter contendo regra de negócio;
  • portas gigantes;
  • duplicar entidades por camada;
  • container global;
  • testar apenas com mocks;
  • confundir pasta com arquitetura.

Checklist

  • núcleo independente;
  • portas orientadas a capacidades;
  • adapters pequenos;
  • composition root explícito;
  • erros traduzidos na borda;
  • testes do núcleo rápidos;
  • integração para adapters;
  • sem abstrações desnecessárias.

Conclusão

Arquitetura Hexagonal no Node.js torna regras de negócio independentes de HTTP, banco e fornecedores. Portas definem o que o núcleo precisa; adapters implementam como a interação acontece.

Use o padrão para proteger áreas que realmente mudam e manter casos de uso testáveis. A arquitetura deve reduzir acoplamento, não multiplicar arquivos sem propósito.

Consulte o artigo de Alistair Cockburn sobre Arquitetura Hexagonal e a documentação de testes do Node.js.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita