3
respostas

[Dúvida] Onde colocar erros HTTPS?

Boa noite!

Tenho dúvidas de onde implementar os erros https. A meu ver essa responsabilidade deveria ficar no controller, mas não consigo ver uma forma clara de fazer isso.

Hoje eu faço da seguinte forma:

  • Cadastrar um usuário com e-mail único.
    • Controller recebe as informações e chama o service.
    • No service eu vou no banco e valido se o e-mail existe.
    • Se sim eu retorno o 'throw new NotFoundException' (no service) informando que já existe.

Isso seria a melhor forma? O ideal não seria esse 'throw new NotFoundException' ser no controller, por se tratar de um erro http?

Pensei em fazer dessa forma:

  • Cadastrar um usuário com e-mail único.
    • Controller recebe as informações e chama o service.
    • No service eu vou no banco e valido se o e-mail existe.
    • Se não existe, o service retorna um usuario vazio ou null.
    • Controller recebe esse usuario (do service) e valida se é null
      • if(!usuario) 'throw new NotFoundException'
    • Se não for null chama o service para criar o usuario

Dessa forma entendo que a responsabilidade do erro http fica no controller, porém entendo que uma parte da regra de negócio fica dentro do controller.

Estou implementando algo erroneamente? Ou isso é mero detalhe?

3 respostas

Oi Gustavo!

Normalmente deixamos as responsabilidades referentes a requisições e respostas com o controller mesmo, isso inclui manejar o que é recebido do service e "traduzir" isso em mensagens de erro e códigos http adequados.

Talvez a dúvida esteja na forma como a validação é passada para o service e de volta para o controller.

Ao invés do service verificar se email é null, retornar o resultado para o controller e, dependendo desse resultado chamar o service para criar o usuário, pode-se fazer toda a verificação direto entre service-repository, e o controller atuar apenas de acordo com o retorno recebido. O TypeORM, por exemplo, trabalha com o método findOneOrFail() que procura um registro (por exemplo, um e-mail) e, caso não encontre, retorna uma promessa "rejeitada".

Um exemplo poderia ser assim (usando o findOneOrFail() mas poderia ser qualquer outro método:

//service
findOne(email: string): Promise<string>{
  return this.userRepository.findOneOrFail(email);
}

//controller
@Get(':email')
async findOne(@Param('email') email: string) {
  try {
    await this.service.findOne(email)
  } catch (error) { 
    throw new HttpException({
    status: HttpStatus.FORBIDDEN,
    error: 'This is a custom message',
  }, HttpStatus.FORBIDDEN, {
    cause: error
  });
  }
}

O exemplo de manipulação de exceções acima é o que está na documentação do Nest.js. Assim, toda a parte de negócio (verificar se um e-mail existe antes de criar) continua no service e o manejo das requisições http fica com o controller.

Espero ter ajudado!

Bons estudos ;)

Bom dia!

Juliana, obrigado pela resposta, mais ainda não ficou claro, deve ser meu nível de conhecimento xD.

Hoje não utilizamos nenhum ORM, nosso banco é oracle e optamos por utilizar a lib oracledb.

No seu exemplo retirado da doc, é apenas uma busca simples, uma única validação. E quando eu tenho 10 validações no service por exemplo?

Pensando nisso, como poderia implementar essas tratativas de erro sem o ORM?

Hoje está dessa forma (ainda tratando os erros http no service), peguei uma api que estou desenvolvendo.

// REPOSITORY 
// tbm tem o buscarItensDaNf
async buscarNf(nr_sequencia: number): Promise<InfoNotaFiscal> {
    // sql complexo

    let conexao: Connection;
    let resultado: InfoNotaFiscal[];
    try {
      conexao = await this.oracleService.conexao(ORACLE);

      const { rows } = await conexao.execute<InfoNotaFiscal>(sql, bind);
      resultado = rows;
    } catch (error) {
      throw new InternalServerErrorException('Erro interno.');
    } finally {
      if (conexao) {
        await conexao.close();
      }
    }

    const resultadoTemp: InfoNotaFiscal =
      resultadoLowerCase<InfoNotaFiscal>(resultado).shift();

    return resultadoTemp;
  }


// SERVICE
async montarNotaFiscal(nr_sequencia: number): Promise<NotaFiscal> {
    const infoNotaFiscal = await this.notaFiscalRepository.buscarNf(
      nr_sequencia,
    );

    // erro http 404
    if (!infoNotaFiscal) {
      throw new NotFoundException(
        'nr_sequencia da nota fiscal não localizado.',
      );
    }

 // busca os itens da nf (retorna um array)
    const itensNotaFiscal = await this.notaFiscalRepository.buscarItensDaNf(
      nr_sequencia,
    );

    // erro http 404
    if (itensNotaFiscal.length <= 0) {
      throw new NotFoundException('Nota fiscal não possui itens.');
    }

    const notaFiscal = new NotaFiscal({
      ...infoNotaFiscal,
      itens: itensNotaFiscal,
    });

    return notaFiscal;
  }


// controller
  @Get(':nr_sequencia')
  async buscarNf(@Param('nr_sequencia', ParseIntPipe) nr_sequencia: number) {
    const notaFiscal = await this.notaFiscalService.montarNotaFiscal(
      nr_sequencia,
    );

    const resultado = await this.efoodService.enviarNotaFiscal(notaFiscal);
    return resultado;
  }

Nos comentários "//erro http 404" entendo que deve ser feito no controller. Nesse exemplo acima, podemos ver que eu tenho que tratar qnd a nf não é localiza ou qnd ela não tem itens, são 2 momentos diferentes.

Talvez esteja dando responsabilidade de mais para a função montarNotaFiscal e isso está me gerando dúvidas?

Fico no aguardo!

Oi Gustavo!

Sim, a validação das NFs em si é responsabilidade do serviço, mas penso que nesse caso seria válido criar um ou mais métodos privados, dentro da classe do serviço, para a validação; assim essa responsabilidade pode ser retirada de montarNotaFiscal() como era a sua dúvida. Dessa forma você também poderá reaproveitar melhor os métodos de validação (podendo utilizá-los para uma NF ou várias, por exemplo) e também retornar erros diferentes para cada caso. Dependendo da quantidade de validações, você pode também considerar uma classe separada do serviço principal, destinada apenas aos métodos de validação. O Nestjs tem uma lib de validação de onde é possível estender classes de validação se for o caso.

Neste link o autor dá uma forma de fazer essa separação, mas você pode criar os métodos e classes da forma como achar mais conveniente para o seu projeto.

A partir do que o serviço retornar, aí o controlador decide o que "faz" com o erro e qual o método HTTP mais apropriado para enviar na resposta da requisição.

Apenas um detalhe: talvez 404 não seja o melhor código de erro no caso de não existirem itens na NF (a condição itensNotaFiscal.length <= 0), pois se a NF em si existe mas não existe nenhum item faturado dentro dela, aparentemente seria uma falha de negócio pois não deveria ser possível a geração de uma NF sem nenhum item... (olhando a partir do trecho que você enviou)

Bons estudos ;)

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software