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!
Se preferir, você pode acompanhar este mesmo conteúdo no vídeo abaixo.
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?
1 2 3 4 5 6 7 8 |
try{ //seu código aqui } catch(error){ //seu tratamento de erro aqui } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
const express = require('express'); const app = express(); app.get('/teste1', (req, res, next) => { res.send('teste1'); }) app.get('/teste2', (req, res, next) => { try { throw new Error('teste2 deu erro'); } catch (error) { console.log(error); res.sendStatus(500); } }) app.get('/teste3', (req, res, next) => { throw new Error('teste3 deu erro'); }) app.listen(3000, () => { console.log('Server running at 3000'); }) |
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.
1 2 3 4 5 6 7 8 9 10 |
app.get('/teste3', (req, res, next) => { throw new Error('teste3 deu erro'); }) app.use((error, req, res, next) => { console.log('error middleware'); res.sendStatus(500); }) |
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.
1 2 3 4 5 6 7 8 9 10 |
app.get('/teste2', (req, res, next) => { try { throw new Error('teste2 deu erro'); } catch (error) { console.log(error); next(error); } }) |
A partir da v5 do Express você também tem suporte a captura de erros assíncronos, então pode testar o código abaixo que também vai funcionar.
1 2 3 4 5 |
app.get('/teste3', async (req, res, next) => { throw new Error('teste3 deu erro'); }) |
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.
E se quiser aprender a fazer logging, confira este tutorial!
Um abraço e sucesso.
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.
Estava procurando uma solução mais simples pra tratar erros, e a sua meu amigo, foi perfeita heheheh. Muito obrigado. Bom trabalho 😀
Fico feliz que tenha lhe ajudado!
Luiz, peço sua orientação para o seguinte:
Quero publicar um site que já roda normalmente em ‘localhost’.
Mas, ao tentar rodá-lo no navegador, falha, apresentando a seguinte mensagem de erro: Uncaught TypeError: Failed to resolve module specifier “express”. Relative references must start with either “/”, “./”, or “../”.
Que fazer? E se você tiver algum curso que trate do assunto, por favor, informe. Obrigado. Resposta para e-mail: [email protected].
Ao que parece você está precisando estudar deploy de aplicações. Tem tutoriais aqui no blog usando AWS, Digital Ocean e Heroku. Também é ensinado em todos meus cursos de programação.