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

Express 5: Erros Assíncronos

Atualizado em: 18 de agosto de 2026

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

Express 5 com erros assíncronos é um tema importante para quem desenvolve serviços modernos com JavaScript no servidor. Não basta fazer uma demonstração funcionar no computador local: uma solução profissional precisa ter contratos claros, tratamento de falhas, segurança, testes, observabilidade e um processo de implantação previsível.

Neste guia, você aprenderá a aplicar Express 5 com erros assíncronos de forma prática, entendendo a arquitetura, os principais componentes, os riscos mais comuns e as decisões que tornam o projeto mais fácil de manter. O objetivo é sair de um exemplo isolado e chegar a uma base que possa evoluir sem depender de improvisos.

O que é Express 5 com erros assíncronos?

Express 5 é a evolução do conhecido framework HTTP para Node.js. Uma mudança importante é que handlers e middlewares que retornam Promises encaminham rejeições automaticamente para o middleware de erro. Isso reduz wrappers repetitivos, mas não elimina a necessidade de classificar falhas, validar entrada e produzir respostas seguras.

Em aplicações Node.js, essa abordagem se encaixa bem em sistemas orientados a eventos e operações de entrada e saída. Para revisar os fundamentos da plataforma, leia o que é Node.js. Se você ainda está montando seu primeiro backend, o tutorial sobre como criar uma API com Node.js oferece uma visão complementar.

Quando vale a pena usar?

A abordagem é indicada para equipes que já usam Express ou precisam de um ecossistema amplo de middlewares. Ela funciona bem em APIs REST, backends tradicionais e serviços de integração. Migrações devem ser testadas porque padrões de rotas, assinaturas de métodos e comportamentos antigos podem ter mudado entre versões.

A decisão deve considerar o problema real, a experiência da equipe, a infraestrutura disponível e o custo de operação. Uma tecnologia pode ser excelente e ainda assim ser inadequada quando aumenta a complexidade sem gerar benefício mensurável. Comece pequeno, defina critérios de sucesso e valide o comportamento sob carga e falhas.

Preparando o projeto

Crie uma pasta dedicada, inicialize o package.json e fixe uma versão suportada do Node.js no arquivo de configuração do projeto. Use variáveis de ambiente para endereços, credenciais e opções de execução, mas valide tudo no início do processo para evitar falhas tardias.

npm init -y
npm install express
npm install --save-dev supertest

Separe dependências de produção das ferramentas de desenvolvimento. Ative lint, formatação e testes no pipeline de integração contínua. O artigo sobre deploy com GitHub Actions mostra como automatizar verificações antes que uma alteração chegue ao servidor.

Exemplo inicial

Uma função async pode lançar uma exceção ou retornar uma Promise rejeitada. No Express 5, o erro segue para o middleware de quatro argumentos.

import express from 'express';

const app = express();
app.use(express.json({ limit: '100kb' }));

app.get('/orders/:id', async (req, res) => {
  const order = await orderRepository.findById(req.params.id);

  if (!order) {
    const error = new Error('Order not found');
    error.statusCode = 404;
    throw error;
  }

  res.json(order);
});

app.use((error, req, res, next) => {
  const status = Number(error.statusCode) || 500;
  res.status(status).json({
    code: status === 404 ? 'ORDER_NOT_FOUND' : 'INTERNAL_ERROR',
    requestId: req.id
  });
});

O middleware de erro precisa ser registrado depois das rotas. O parâmetro next deve existir na assinatura, mesmo quando não é usado. Em produção, não envie error.message para falhas inesperadas, pois ela pode revelar detalhes internos.

Estrutura recomendada

Mantenha os handlers finos: eles traduzem HTTP para um caso de uso, recebem o resultado e geram a resposta. Regras de negócio ficam fora do objeto req e res. Crie middlewares separados para identificação da requisição, autenticação, autorização, validação e tratamento de erro.

  • config: leitura e validação de ambiente;
  • domain: regras de negócio independentes do transporte;
  • application: casos de uso e orquestração;
  • infrastructure: banco, filas, rede e integrações;
  • interfaces: HTTP, comandos, eventos ou tarefas agendadas;
  • tests: unidades, integração e cenários de contrato.

Essa separação reduz acoplamento e permite substituir bibliotecas sem reescrever regras de negócio. Evite criar camadas vazias apenas para seguir um padrão: cada módulo deve proteger uma responsabilidade concreta.

Contratos e validação

Dados externos são sempre não confiáveis. Valide corpo, parâmetros, headers, eventos e respostas de serviços terceiros. Defina tamanho máximo, formatos permitidos e mensagens de erro consistentes. Schemas executáveis aproximam documentação e comportamento real; veja também o guia de validação com Zod no TypeScript.

Valide params, query e body antes de chamar o caso de uso. Converta tipos explicitamente, porque valores de rota e query chegam como strings. Normalize erros do validador em um formato único, com caminho do campo, código e mensagem apropriada.

Tratamento de erros

Classifique falhas em categorias: entrada inválida, autenticação, autorização, recurso ausente, conflito, indisponibilidade temporária e erro interno. A resposta pública deve ser estável e não pode expor stack trace, consulta SQL, segredo ou detalhes da infraestrutura.

Crie classes ou códigos de erro do domínio e um mapeador central. Diferencie falhas operacionais esperadas de bugs. Após iniciar o envio da resposta, delegue para o error handler padrão ou encerre a conexão com cuidado, pois não é possível trocar status e headers já enviados.

function errorHandler(error, req, res, next) {
  if (res.headersSent) {
    return next(error);
  }

  const map = {
    ValidationError: [400, 'INVALID_REQUEST'],
    UnauthorizedError: [401, 'UNAUTHORIZED'],
    NotFoundError: [404, 'NOT_FOUND'],
    ConflictError: [409, 'CONFLICT']
  };

  const [status, code] =
    map[error.name] ?? [500, 'INTERNAL_ERROR'];

  res.status(status).json({
    code,
    requestId: req.id
  });
}

Segurança

A segurança deve fazer parte da arquitetura desde o início. Aplique privilégio mínimo, valide todas as fronteiras e trate credenciais como dados sensíveis. Para Express 5 com erros assíncronos, priorize:

  • limite JSON, formulários e uploads antes do parse;
  • configure proxy confiável para obter IP e protocolo corretos;
  • não exponha stack trace nem mensagens internas;
  • aplique autenticação antes das rotas protegidas;
  • valide redirecionamentos e URLs fornecidas pelo usuário;
  • use cookies HttpOnly, Secure e SameSite quando houver sessão.

Registre eventos de segurança sem armazenar tokens completos, senhas ou dados pessoais desnecessários. Revise dependências e mantenha um processo claro para corrigir vulnerabilidades.

Desempenho e capacidade

Otimização começa com medição. Defina indicadores como latência, taxa de erro, uso de memória, CPU, tamanho de filas e tempo de dependências. O guia sobre como otimizar APIs RESTful em Node.js detalha princípios que também se aplicam aqui.

  • evite middlewares globais desnecessários;
  • não execute trabalho de CPU pesado no handler;
  • reutilize conexões e pools;
  • defina timeouts no servidor e nas dependências;
  • faça paginação com limites máximos;
  • meça o custo de serialização e logs.

Teste com carga representativa e inclua cenários de falha. Uma solução que funciona apenas com dependências saudáveis não está pronta para produção.

Observabilidade

Adicione requestId no início da cadeia e inclua método, rota, status e duração no log final. Registre a exceção apenas uma vez para evitar duplicação. Métricas devem agrupar por padrão de rota, não pela URL completa, para impedir cardinalidade excessiva.

Use logs estruturados em JSON e inclua um identificador de correlação. Métricas devem mostrar volume, sucesso, falhas e duração. Traces distribuídos ajudam a encontrar gargalos quando uma operação atravessa vários serviços, mas precisam de amostragem para controlar custo.

Testes automatizados

Teste o app sem chamar listen. Use Supertest ou um cliente HTTP local para confirmar rotas, validação e o middleware de erro. Inclua rejeições assíncronas, recursos ausentes, conflito, timeout e falha depois de headers enviados.

import test from 'node:test';
import assert from 'node:assert/strict';
import request from 'supertest';
import { buildApp } from './app.js';

test('encaminha rejeição async', async () => {
  const app = buildApp({
    findOrder: async () => {
      throw new Error('database unavailable');
    }
  });

  const response = await request(app)
    .get('/orders/123');

  assert.equal(response.status, 500);
  assert.equal(response.body.code, 'INTERNAL_ERROR');
});

Evite testes dependentes de ordem, relógio real ou serviços externos instáveis. Injete relógio, geradores de identificadores e clientes de infraestrutura. Para fundamentos, consulte testes unitários com Jest.

Implantação e operação

Mantenha o Express atrás de um proxy reverso configurado e teste trust proxy. A aplicação deve receber sinais, parar o servidor HTTP, aguardar requisições em andamento e fechar banco, filas e clientes externos. Use limites de tempo para que o encerramento não fique preso.

Implemente graceful shutdown: ao receber um sinal de encerramento, pare de aceitar trabalho novo, conclua o que estiver em andamento dentro de um prazo e feche conexões. Configure health checks que diferenciem processo vivo de serviço pronto para receber tráfego.

Erros comuns

  • Adicionar try/catch em toda rota: isso repete código e pode esquecer next.
  • Enviar a mensagem original: erros internos podem vazar dados sensíveis.
  • Registrar error handler antes das rotas: ele não receberá falhas posteriores.
  • Misturar regra de negócio com res: os casos de uso ficam difíceis de testar.
  • Ignorar headersSent: uma segunda resposta causa comportamento incorreto.

Checklist antes de publicar

  • migração para Express 5 testada;
  • handlers async sem wrappers desnecessários;
  • middleware de erro ao final;
  • classes de erro mapeadas;
  • validação de params, query e body;
  • limites e timeouts definidos;
  • logs com requestId;
  • cenários de rejeição cobertos por testes.

Referências oficiais

Conteúdos relacionados

Conclusão

Express 5 simplifica o encaminhamento de erros em funções assíncronas, mas a qualidade da API ainda depende de uma política central. Handlers finos, erros de domínio, validação antecipada e respostas estáveis produzem um sistema muito mais previsível do que uma coleção de try/catch independentes.

O caminho mais seguro é implementar uma versão pequena, observável e testável, medir seu comportamento e evoluir com base em dados. Quando contratos, limites e falhas são tratados explicitamente, Express 5 com erros assíncronos deixa de ser apenas uma funcionalidade e se torna uma parte confiável da plataforma.

Os 10 Melhores Cursos de Programação de 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