Error Handling em Node.js com Express

Este tutorial possui versão em videoaulas em meu curso FullStack JS!

Todo mundo projeta as suas aplicações para que funcionem, certo?

Mas elas funcionam sempre?

É claro que não!

Aí mora uma falha de design de software muito comum: raramente os programadores pensem na manipulação dos erros das aplicações nas quais trabalham, o que gera dores de cabeça enormes no médio e longo prazo, quando o sistema já está em produção e precisamos fazer troubleshooting, mudar tecnologia de logging ou até mesmo manipular os erros de forma mais eficiente.

Que tal aprender a fazer error handling em Express de forma elegante e que te permita evoluir a sua aplicação com qualidade ao longo do tempo?

Esse é o assunto do tutorial de hoje!

Atenção: este tutorial é para quem já sabe programar ao menos o básico de Node.js com Express. Não vou cobrir aspectos básicos do entendimento destas tecnologias e, se estiver buscando isso, comece por meus livros ou esta página.

#1 – Voltando ao Básico

O primeiro passo é obviamente revisitar o assunto manipulação de erro em JavaScript. Basicamente quando queremos capturar um erro que possa ser lançado em certo bloco de código, usamos try/catch, certo?

Se um erro acontecer dentro do bloco try, o fluxo será redirecionado para o bloco catch onde você terá acesso a um objeto error com os dados do erro, permitindo que você trate, registre e devolva ao usuário uma resposta mais amigável.

O grande problema do try/catch é…bem, que você tem de escrevê-lo em todos os pontos da sua aplicação onde não quer que um erro possa estourar e com isso prejudicar a experiência do usuário.

Não fosse o bastante, se você estiver com uma web API em Node.js feita com Express, se você tiver o estouro de um erro sem o devido tratamento, o seu webserver pode cair! Sim, porque erros não tratados no Event Loop simplesmente podem derrubar o Event Loop! E isso não é uma característica exclusiva do Node.js ou do JavaScript, programas de computador em geral são encerrados automaticamente se der uma exceção não tratada no seu fluxo principal!

Assim, vamos considerar um pequeno exemplo de webapi Express onde temos três rotas, uma que funciona, uma que dá erro mas o mesmo é tratado e outra que dá erro e o mesmo não é tratado.

Não esqueça de instalar a dependência do express antes de rodar este projeto com “npm install”.

Teste as 3 rotas usando Postman ou mesmo no seu navegador. Consegue perceber a diferença entre as 3? Em especial a 2 e 3, pois na 2 conseguimos tratar o erro e dar algum destino diferente para a requisição, enquanto que na 3 estoura um erro grosseiro e que não temos controle, inclusive expondo nosso servidor ao requisitante.

Jamais deixe suas rotas desta forma!

#2 – Error Middleware

Uma forma de fazer o gerenciamento de erros de forma mais profissional é centralizando-o através de um error middleware.

O Express é todo organizado através de middlewares de processamento e existe um middleware especial que chamamos de Error Middleware que serve como destino default para todos os erros gerados e não tratados no event loop.

Enquanto que um middleware normal possui 3 parâmetros (req, res e next), o Error Middleware é criado passando um parâmetro a mais, que na verdade deve ser o primeiro: error. Além disso, ele deve ser o último middleware na sua cadeia de processamento.

No exemplo acima, criei o error middleware logo após a última rota. Experimente subir novamente sua aplicação e testar a rota 3. Verá que apesar de ela não possuir try/catch, seu fluxo será redirecionado para o error middleware automaticamente quando o erro estourar, simplificando bastante o tratamento de erros pois agora ele estará centralizado.

Ainda assim, nas rotas que você desejar ainda ter um try/catch personalizado, você pode mantê-lo e redirecionar para o error middleware opcionalmente, com a função next, passando o erro como único argumento.

Estas duas abordagens de uso do Error Middleware resolvem parte do problema de tratamento unificado de erros. Vamos falar de um novo problema na sequência.

Curso Node.js e MongoDB
Curso Node.js e MongoDB

#3 – Async Errors

Lembra que eu falei que todos erros não tratados no Event Loop vão cair automaticamente no Error Middleware?

Mas e os erros que não estourarem no Event Loop? O que acontece com eles?

Experimente fazer este pequeno ajuste no seu código, dizendo que o middleware é assíncrono.

Essa é uma situação que forcei aqui, mas certamente você conhece muitos cenários em que isso se aplica, principalmente quando estamos trabalhando com banco de dados, APIs externas, etc.

Agora, ao rodar sua web API e testar essa rota GET /teste3, vai notar que ela vai ficar pendurada. Ela não vai cair no Error Middleware e nem sequer vai responder a request. Depois de 2 minutos, vai cair a requisição por timeout, que é a configuração padrão da lib http do Node.js que o Express usa.

Se você olhar o seu console, vai ver a seguinte mensagem.

Ou seja, ocorreu um erro dentro de uma função async. Funções async não rodam no Event Loop, mas sim no Thread Pool em background, apenas retornando ao Event Loop depois que terminou seu processamento assíncrono.

Como não tratamos o erro com try/catch ou com Promise Reject, não foi possível à função retornar ao Event Loop e consequentemente o Express nunca saberá desse erro, caindo por timeout depois de algum tempo.

Neste caso, ou você usa try/catch nos seus middlewares async, chamando o Error Middleware com next (como mostrei anteriormente), ou adiciona mais uma dependência que vai avisar o Error Middleware de erros async, que é o que eu recomendo que você faça.

O Express Async Errors é um pacote minúsculo e muito prático para consertar essa falha de arquitetura do Express que ainda não se adaptou ao mundo async/await do ES6.

Para usar a dependência, basta referenciá-la o mais cedo possível na sua aplicação e ela magicamente vai resolver o gap pra gente.

Com isso, cobrimos tanto os erros sync quanto async, garantindo que nosso Error Middleware dará conta de qualquer erro não tratado em nossa aplicação.

Como próximos passos, que eu não vou abordar hoje pois este tutorial já está se tornando extenso, você pode utilizar Custom Errors na sua aplicação para que o Error Middleware consiga identificar os tipos de erro e dar retornos apropriados.

Deixa nos comentários se acha interessante esse assunto, para uma continuação deste artigo.

Um abraço e sucesso.

Curtiu o tutorial? Conheça minha formação completa de Web FullStack com JavaScript, onde abordo este assunto na prática com videoaulas.

Curso FullStack
Curso FullStack

Publicado por

Luiz Duarte

Pós-graduado em computação, professor, empreendedor, autor, Agile Coach e programador nas horas vagas.