Implementar o tratamento de erros ao usar a API Fetch

Este artigo demonstra algumas abordagens de tratamento de erros ao trabalhar com a API Fetch. A API Fetch permite fazer uma solicitação a um recurso de rede remoto. Quando você faz uma chamada de rede remota, sua página da Web fica sujeita a vários possíveis erros de rede.

As seções a seguir descrevem possíveis erros e como escrever um código que forneça um nível razoável de funcionalidade resistente a erros e condições de rede inesperadas. Um código resiliente mantém os usuários satisfeitos e mantém um nível padrão de serviço para seu site.

Prever possíveis erros de rede

Esta seção descreve um cenário em que o usuário cria um novo vídeo chamado "My Travels.mp4" e, em seguida, tenta fazer upload do vídeo em um site de compartilhamento de vídeo.

Ao trabalhar com a busca, é fácil considerar o caminho da felicidade em que o usuário envia o vídeo. No entanto, há outros caminhos que não são tão simples, mas que os desenvolvedores da Web precisam planejar. Esses caminhos (infelizes) podem acontecer devido a erros do usuário, condições ambientais inesperadas ou a um bug no site de compartilhamento de vídeos.

Exemplos de erros do usuário

  • O usuário carrega um arquivo de imagem (como JPEG) em vez de um arquivo de vídeo.
  • O usuário começa a enviar o arquivo de vídeo errado. Em seguida, no meio do upload, o usuário especifica o arquivo de vídeo correto para enviar.
  • O usuário acidentalmente clica em "Cancelar upload" enquanto o vídeo está sendo enviado.

Exemplos de mudanças ambientais

  • A conexão de Internet fica off-line durante o upload do vídeo.
  • O navegador será reiniciado durante o upload do vídeo.
  • Os servidores do site de compartilhamento de vídeo são reiniciados durante o upload do vídeo.

Exemplos de erros com o site de compartilhamento de vídeos

  • O site de compartilhamento de vídeo não pode processar um nome de arquivo com um espaço. Em vez de "My Travels.mp4", ele espera um nome como "My_Travels.mp4" ou "MyTravels.mp4".
  • O site de compartilhamento de vídeo não pode fazer upload de um vídeo que exceda o tamanho máximo de arquivo aceitável.
  • O site de compartilhamento de vídeo não é compatível com o codec do vídeo enviado.

Esses exemplos podem e acontecem no mundo real. Talvez você já tenha visto esses exemplos no passado. Vamos escolher um exemplo de cada uma das categorias anteriores e discutir os seguintes pontos:

  • Qual será o comportamento padrão se o serviço de compartilhamento de vídeo não puder lidar com o exemplo dado?
  • O que o usuário espera que aconteça no exemplo?
  • Como podemos melhorar o processo?
Ação O usuário começa a enviar o arquivo de vídeo errado. Em seguida, no meio do upload, o usuário especifica o arquivo de vídeo correto para enviar.
O que acontece por padrão O upload do arquivo original continua em segundo plano enquanto o novo arquivo é enviado ao mesmo tempo.
O que o usuário espera O usuário espera que o upload original seja interrompido para que nenhuma largura de banda extra da Internet seja desperdiçada.
O que pode ser melhorado O JavaScript cancela a solicitação de busca do arquivo original antes que o upload do novo arquivo comece.
Ação O usuário perde a conexão de Internet no meio do processo de envio do vídeo.
O que acontece por padrão A barra de progresso do upload parece estar travada em 50%. Eventualmente, a API Fetch atinge o tempo limite, e os dados enviados são descartados. Quando a conectividade com a Internet retornar, o usuário precisará fazer o upload do arquivo novamente.
O que o usuário espera O usuário espera ser notificado quando não for possível fazer upload do arquivo e espera que o upload seja retomado automaticamente a 50% quando estiver on-line novamente.
O que pode ser melhorado A página de upload informa o usuário sobre problemas de conectividade com a Internet e garante que o upload será retomado quando isso acontecer.
Ação O site de compartilhamento de vídeo não pode processar um nome de arquivo com um espaço. Em vez de "Minhas viagens.mp4", são esperados nomes como "Minhas viagens.mp4" ou "Minhas viagens.mp4".
O que acontece por padrão O usuário precisa aguardar a conclusão do upload. Depois que o upload do arquivo for concluído e a barra de progresso mostrar "100%", a barra de progresso exibirá a mensagem: "Tente novamente".
O que o usuário espera O usuário espera ser informado sobre as limitações de nome de arquivo antes do início do upload, ou pelo menos no primeiro segundo após o upload.
O que pode ser melhorado Idealmente, o serviço de compartilhamento de vídeo suporta nomes de arquivos com espaços. Outras opções são notificar o usuário sobre as limitações do nome de arquivo antes de iniciar o upload. Ou o serviço de compartilhamento de vídeo deve rejeitar o upload com uma mensagem de erro detalhada.

Solucionar erros com a API Fetch

Os exemplos de código a seguir usam await de nível superior (suporte a navegadores) porque esse recurso pode simplificar o código.

Quando a API Fetch gera erros

Esse exemplo usa uma instrução de bloco try/catch para capturar erros gerados no bloco try. Por exemplo, se a API Fetch não conseguir buscar o recurso especificado, um erro será gerado. Em um bloco catch como esse, forneça uma experiência do usuário significativa. Se um ícone de carregamento, uma interface do usuário comum que representa algum tipo de progresso, for mostrado ao usuário, você poderá realizar as seguintes ações em um bloco catch:

  1. Remova o ícone de carregamento da página.
  2. Forneça mensagens úteis que expliquem o que deu errado e quais opções o usuário pode escolher.
  3. Com base nas opções disponíveis, apresente um botão "Tentar novamente" ao usuário.
  4. Em segundo plano, envie os detalhes do erro para seu serviço de rastreamento de erros ou para o back-end. Essa ação registra o erro para que ele possa ser diagnosticado posteriormente.
try {
  const response = await fetch('https://website');
} catch (error) {
  // TypeError: Failed to fetch
  console.log('There was an error', error);
}

Posteriormente, enquanto diagnostica o erro registrado, crie um caso de teste para capturar esse erro antes que os usuários saibam que há algo errado. Dependendo do erro, o teste pode ser de unidade, integração ou aceitação.

Quando o código de status da rede representa um erro

Este exemplo de código faz uma solicitação a um serviço de teste HTTP que sempre responde com o código de status HTTP 429 Too Many Requests. É interessante observar que a resposta não chega ao bloco catch. Um status 404, entre alguns códigos de status, não retorna um erro de rede, mas é resolvido normalmente.

Para verificar se o código de status HTTP foi bem-sucedido, você pode usar uma das seguintes opções:

  • Use a propriedade Response.ok para determinar se o código de status estava no intervalo de 200 a 299.
  • Use a propriedade Response.status para determinar se a resposta foi bem-sucedida.
  • Use outros metadados, como Response.headers, para avaliar se a resposta foi bem-sucedida.
let response;

try {
  response = await fetch('https://httpbin.org/status/429');
} catch (error) {
  console.log('There was an error', error);
}

// Uses the 'optional chaining' operator
if (response?.ok) {
  console.log('Use the response here!');
} else {
  console.log(`HTTP Response Code: ${response?.status}`)
}

A prática recomendada é trabalhar com as pessoas da sua organização e da equipe para entender possíveis códigos de status de resposta HTTP. Às vezes, os desenvolvedores de back-end, as operações de desenvolvimento e os engenheiros de serviço podem fornecer insights exclusivos sobre possíveis casos extremos que talvez você não tenha previsto.

Quando ocorre um erro ao analisar a resposta da rede

Este exemplo de código demonstra outro tipo de erro que pode surgir com a análise de um corpo de resposta. A interface Response oferece métodos convenientes para analisar diferentes tipos de dados, como texto ou JSON. No código a seguir, uma solicitação de rede é feita para um serviço de teste HTTP que retorna uma string HTML como o corpo da resposta. No entanto, há uma tentativa de analisar o corpo da resposta como JSON, o que gera um erro.

let json;

try {
  const response = await fetch('https://httpbin.org/html');
  json = await response.json();
} catch (error) {
  if (error instanceof SyntaxError) {
    // Unexpected token < in JSON
    console.log('There was a SyntaxError', error);
  } else {
    console.log('There was an error', error);
  }
}

if (json) {
  console.log('Use the JSON here!', json);
}

Você deve preparar seu código para aceitar uma variedade de formatos de resposta e verificar se uma resposta inesperada não quebra a página da Web para o usuário.

Considere o seguinte cenário: você tem um recurso remoto que retorna uma resposta JSON válida e ele é analisado com o método Response.json(). Pode acontecer de o serviço ficar inativo. Depois de inativo, uma 500 Internal Server Error é retornada. Se as técnicas adequadas de tratamento de erros não forem usadas durante a análise de JSON, a página poderá ser interrompida para o usuário, porque um erro não processado será gerado.

Quando a solicitação de rede precisa ser cancelada antes de ser concluída

Neste exemplo de código, um AbortController é usado para cancelar uma solicitação em andamento. Uma solicitação em andamento é uma solicitação de rede que foi iniciada, mas não foi concluída.

Os cenários em que pode ser necessário cancelar uma solicitação em andamento podem variar, mas isso depende do caso de uso e do ambiente. O código a seguir demonstra como transmitir um AbortSignal para a API Fetch. O AbortSignal é anexado a um AbortController, e o AbortController inclui um método abort(), o que significa para o navegador que a solicitação de rede precisa ser cancelada.

const controller = new AbortController();
const signal = controller.signal;

// Cancel the fetch request in 500ms
setTimeout(() => controller.abort(), 500);

try {
  const url = 'https://httpbin.org/delay/1';
  const response = await fetch(url, { signal });
  console.log(response);
} catch (error) {
  // DOMException: The user aborted a request.
  console.log('Error: ', error)
}

Conclusão

Um aspecto importante do tratamento de erros é definir as várias partes que podem dar errado. Para cada cenário, verifique se você tem um substituto adequado para o usuário. Em relação a uma solicitação de busca, faça a si mesmo perguntas como:

  • O que acontece se o servidor de destino ficar inativo?
  • O que acontece se a busca receber uma resposta inesperada?
  • O que acontece se a conexão de Internet do usuário falhar?

Dependendo da complexidade da página, você também pode esboçar um fluxograma que descreve a funcionalidade e a interface do usuário para diferentes cenários.