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

Service Layer no Node.js: organize casos de uso

Atualizado em: 13 de outubro de 2026

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

Service Layer no Node.js é uma camada que coordena casos de uso da aplicação. Ela recebe dados já interpretados pela entrada HTTP, aplica regras, chama repositories, publica eventos e define a transação necessária para concluir uma operação.

Controllers devem lidar com protocolo. Repositories devem lidar com persistência. A Service Layer conecta essas partes sem depender de detalhes de rota, banco ou framework.

Neste guia, você aprenderá responsabilidades, transações, validação, erros, idempotência, testes e boas práticas.

Controller com regra misturada

app.post('/users', async (req, res) => {
  if (!req.body.email) return res.status(400).send();
  const exists = await db.query('SELECT 1 FROM users WHERE email = $1', [req.body.email]);
  if (exists.rowCount) return res.status(409).send();
  const user = await db.query('INSERT ...');
  await queue.publish('user.created', user.rows[0]);
  res.status(201).send(user.rows[0]);
});

A rota conhece validação, SQL, evento e regra de unicidade.

Extraindo o caso de uso

export function criarUsuarioService({ repository, eventBus, idGenerator, clock }) {
  return {
    async criar(input) {
      const exists = await repository.existeEmail(input.email);
      if (exists) throw new EmailAlreadyUsedError(input.email);

      const user = {
        id: idGenerator.next(),
        email: input.email,
        createdAt: clock.now()
      };

      await repository.salvar(user);
      await eventBus.publicar({ type: 'user.created', data: user });
      return user;
    }
  };
}

Controller fino

app.post('/users', async (req, res) => {
  try {
    const user = await userService.criar(req.body);
    res.status(201).json(user);
  } catch (error) {
    responderErro(error, res);
  }
});

O controller traduz HTTP para chamada de aplicação e traduz resultado para HTTP.

Validação de entrada

Validação estrutural deve ocorrer na fronteira: tipos, campos obrigatórios e limites. Regras de negócio permanecem no serviço.

Use JSON Schema conforme JSON Schema no Node.js.

Regras de negócio

Exemplos adequados para a Service Layer:

  • verificar se ação é permitida;
  • calcular transição de estado;
  • coordenar múltiplos repositories;
  • aplicar idempotência;
  • publicar evento após commit;
  • selecionar estratégia de negócio.

Transações

await database.transaction(async (tx) => {
  const users = criarUsuarioRepository(tx);
  const outbox = criarOutboxRepository(tx);

  await users.salvar(user);
  await outbox.adicionar({ type: 'user.created', data: user });
});

O serviço coordena a unidade atômica. Repositories recebem a conexão transacional.

Outbox

Publicar evento diretamente depois do commit pode falhar e deixar o sistema inconsistente. O padrão outbox grava o evento na mesma transação e um worker publica depois.

Idempotência

Casos de uso expostos a retries precisam reconhecer repetição. Veja Idempotency Keys no Node.js.

Erros do domínio

class EmailAlreadyUsedError extends Error {
  code = 'EMAIL_ALREADY_USED';
}

O serviço lança erros estáveis. A camada HTTP decide se o código vira 409, 422 ou outro status.

Não retorne objetos HTTP

Evite retornar { statusCode, body } do serviço. Isso acopla o caso de uso ao protocolo e dificulta reutilização por CLI, fila ou GraphQL.

Dependências

Injete repositories, gateways, clock e logger conforme Dependency Injection no Node.js.

Repository

A persistência deve ser acessada por operações orientadas ao domínio. Veja Repository Pattern no Node.js.

Serviços pequenos

Não crie uma classe com cinquenta métodos para todo o módulo. Organize por caso de uso quando responsabilidades divergem:

criarUsuario
ativarUsuario
bloquearUsuario
alterarEmail

Query services

Leituras complexas podem usar serviços de consulta separados, retornando DTOs otimizados sem reconstruir entidades completas.

Logs

O serviço pode registrar eventos relevantes com contexto, mas não deve repetir cada log de infraestrutura. Use códigos e IDs, nunca senhas ou tokens.

Testes unitários

test('rejeita email existente', async () => {
  const repository = {
    async existeEmail() { return true; }
  };

  const service = criarUsuarioService({ repository, eventBus, idGenerator, clock });

  await assert.rejects(
    () => service.criar({ email: 'a@b.com' }),
    { code: 'EMAIL_ALREADY_USED' }
  );
});

Testes de integração

Verifique transações, constraints e outbox com banco real. Consulte Testes de Integração no Node.js.

Erros comuns

  • service apenas repassa chamada ao repository;
  • service conhece request e response;
  • classe gigante;
  • transação aberta dentro de cada repository;
  • evento publicado antes do commit;
  • dependências globais;
  • misturar validação estrutural e regra;
  • capturar todos os erros.

Checklist

  • casos de uso claros;
  • controllers finos;
  • transações coordenadas;
  • erros estáveis;
  • dependências injetadas;
  • sem detalhes HTTP;
  • idempotência definida;
  • testes unitários e integrados.

Conclusão

Service Layer no Node.js concentra a coordenação dos casos de uso sem misturar protocolo e persistência. Ela oferece um ponto claro para regras, transações, eventos e autorização.

Mantenha serviços focados, com dependências explícitas e erros estáveis. Uma camada útil representa ações do negócio, não apenas métodos genéricos sobre tabelas.

Consulte o catálogo Service Layer de Martin Fowler 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