Tutorial da API JavaScript Fetch: GET, POST, tratamento de erros e tempos limite

  1. Início
  2. Blog
  3. Desenvolvimento de software

Desenvolvimento de Software

Tutorial da API JavaScript Fetch: GET, POST, tratamento de erros e tempos limite

Fetch é a maneira integrada de chamar APIs de JavaScript, mas tem uma surpresa que surpreende quase todo mundo. Aprenda a enviar solicitações, lidar com todo tipo de falha e criar um pequeno ajudante que você possa reutilizar.

9 min de leitura
Tutorial da API JavaScript Fetch: GET, POST, tratamento de erros e tempos limite

Principais pontos

  • fetch() retorna uma promessa para Response e a leitura do corpo leva um segundo await.
  • Erros HTTP como 404 e 500 não rejeitam, portanto sempre verifique response.ok.
  • Para enviar JSON, use JSON.stringify e defina o cabeçalho Content-Type.
  • Fetch não tem opção de tempo limite padrão, então use AbortSignal.timeout().

A maioria dos aplicativos da web modernos conversam com um servidor o tempo todo. A JavaScript Fetch API é a maneira padrão de fazer isso e está integrada aos navegadores e ao Node.js 18 e posterior, portanto, não há nada para instalar.

O uso básico leva duas linhas, mas muitos tutoriais param por aí e deixam de fora a parte que causa bugs reais: o tratamento de falhas. Testamos os exemplos neste guia em um pequeno servidor local no Node.js 24, e a saída mostrada vem dessa execução. example.com no código representa sua própria API. Se as promessas são novas para você, comece com Promessas JavaScript explicadas.

O que é a API de busca?

Fetch é uma interface baseada em promessas para fazer solicitações HTTP. Ele substituiu o antigo, baseado em retorno de chamada XMLHttpRequest, e muitos projetos agora o utilizam em vez de adicionar uma biblioteca para chamadas simples.

Recurso Buscar Axios (biblioteca)
Instalação Construído em Adicionado como uma dependência
Corpo JSON Stringifique você mesmo Automático
Analisar resposta JSON Ligue response.json() Automático
Erros HTTP rejeitados? Não Sim, por padrão
Tempo limite Através de AbortSignal Uma opção timeout

Uma solicitação GET

Fetch faz uma solicitação GET por padrão. Existem duas etapas, e cada uma precisa de await: primeiro chegam os cabeçalhos de resposta e depois você lê o corpo.

const response = await fetch("https://example.com/users/1");
const user = await response.json();

console.log(user);

// { id: 1, name: 'Asha' }

As duas etapas existem porque o corpo pode ser grande e chegar depois dos cabeçalhos. Em um script de navegador, o nível superior await precisa de um módulo, então você normalmente colocará isso dentro de uma função async. Consulte nosso guia JavaScript assíncrono/aguardado.

O objeto Resposta

Antes de ler o corpo, você pode inspecionar a resposta:

console.log(response.status, response.ok, response.headers.get("content-type"));

// 200 true application/json
Propriedade ou método Dá a você
response.ok true para status 200 a 299
response.status O código de status, como 404
response.headers.get(name) Um cabeçalho de resposta
response.json() O corpo analisado como JSON
response.text() O corpo como uma corda
response.blob() Dados binários, como uma imagem

Um corpo pode ser lido apenas uma vez. Chamar json() uma segunda vez falhou em nosso teste:

await res.json();
await res.json();

// TypeError: Body is unusable: Body has already been read

Se você precisar lê-lo duas vezes, ligue para response.clone() primeiro.

A grande surpresa: um 404 não joga

Esta é a coisa mais importante neste artigo. Solicitamos um usuário que não existe:

const res = await fetch("https://example.com/users/999");
console.log(res.status, res.ok);

// 404 false

Nenhuma exceção foi lançada. No que diz respeito à busca, a solicitação funcionou: o servidor foi alcançado e respondeu. A promessa é rejeitada apenas quando nenhuma resposta utilizável chega, como acontece com uma falha de rede. Portanto, um código como este tem um bug oculto:

try {
  const res = await fetch(url);
  const data = await res.json();   // may be an error payload
  showUser(data);                  // runs anyway for 404 and 500
} catch (error) {
  showError();                     // does not run for 404 or 500
}

Verifique nossa folha de referências de códigos de status HTTP para ver o que cada código significa.

Um ajudante reutilizável

Não repita essa verificação em todos os lugares. Embrulhe uma vez:

async function getJson(url, options) {
  const response = await fetch(url, options);
  if (!response.ok) {
    throw new Error(`Request failed with status ${response.status}`);
  }
  return response.json();
}

try {
  await getJson("https://example.com/users/999");
} catch (error) {
  console.log("caught:", error.message);
}

// caught: Request failed with status 404

Agora, erros de HTTP e erros de rede terminam no mesmo catch. Vale a pena ter esta pequena função em todos os projetos. Uma versão real também pode ler uma mensagem de erro do corpo da resposta e manipular uma resposta 204 No Content, que não possui JSON para analisar.

POSTAR dados JSON

Passe um objeto de opções como segundo argumento. Para JSON, você deve fazer duas coisas: converter os dados em uma string e definir o cabeçalho.

const created = await getJson("https://example.com/users", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "Ben" }),
});

console.log(created);

// { id: 2, name: 'Ben', type: 'application/json' }

Nosso servidor de teste repetiu o tipo de conteúdo recebido, confirmando a chegada do cabeçalho. Esquecer esse cabeçalho é uma causa comum de erros confusos no servidor, porque muitos frameworks apenas analisam JSON quando ele é declarado. Para fazer upload de um formulário ou arquivos, passe um objeto FormData como corpo e não defina Content-Type, pois o próprio navegador precisa adicionar um valor de limite.

Outros métodos e opções

Opção Exemplo Objetivo
método "PUT", "PATCH", "DELETE" O método HTTP
cabeçalhos {Autorização: "Portador..." } Solicitar cabeçalhos
corpo JSON.stringify(data) O corpo da solicitação
sinal AbortSignal.timeout(5000) Cancelando
credenciais "incluir" Envio de cookies de origem cruzada
esconderijo "sem loja" Comportamento do cache do navegador

Escolhendo entre REST e outros estilos de API? Nossa comparação de REST vs GraphQL mostra como a busca se encaixa em cada um.

Cadeias de caracteres de consulta

Não crie strings de consulta juntando texto, pois caracteres especiais irão quebrá-las. URLSearchParams cuida da codificação para você:

const params = new URLSearchParams({ q: "red shoes", page: 2 });
console.log(params.toString());

// q=red+shoes&page=2

await getJson(`https://example.com/search?${params}`);

// { q: 'red shoes', page: '2' }

O servidor recebeu red shoes corretamente, com o espaço restaurado.

Tempo limite e cancelamento

O Fetch esperará muito tempo em um servidor lento, a menos que você informe o contrário. AbortSignal.timeout() define um limite. Nosso endpoint de teste levou dois segundos, contra um limite de 200 milissegundos:

try {
  await fetch("https://example.com/slow", { signal: AbortSignal.timeout(200) });
} catch (error) {
  console.log(error.name);
}

// TimeoutError

Para cancelar manualmente, por exemplo, quando um usuário sai de uma página ou digita um novo termo de pesquisa, use um AbortController:

const controller = new AbortController();
const pending = fetch("https://example.com/slow", { signal: controller.signal });

controller.abort();

try {
  await pending;
} catch (error) {
  console.log(error.name);
}

// AbortError

Para executar várias solicitações de uma vez, use Promise.all, que é muito mais rápido do que aguardá-las uma de cada vez:

const [user, search] = await Promise.all([
  getJson("https://example.com/users/1"),
  getJson("https://example.com/search?q=a&page=1"),
]);

Todo tipo de fracasso

Aqui está a aparência de cada falha em nossa execução, além de como diferenciá-las:

Situação O que acontece Como detectá-lo
Servidor retorna 404 ou 500 Promessa cumpre response.ok é falso
O servidor não pode ser alcançado Rejeita com TypeError pegar
Tempo limite atingido Rejeita com TimeoutError error.name
Cancelado manualmente Rejeita com AbortError error.name
O corpo não é JSON válido json() rejeita com SyntaxError pegar

Essa última linha é comum na produção. Um proxy que retorna um 502 geralmente envia uma página de erro HTML. Reproduzimos isso e res.json() lançou um SyntaxError. Marcar response.ok antes de analisar significa que você relata o problema real em vez de um erro de análise confuso.

Dica: teste esses caminhos de falha propositalmente. As ferramentas de desenvolvedor do navegador podem simular estar offline e as ferramentas de teste podem simular uma resposta 500. Nosso guia de teste de API com Postman abrange a verificação do lado da API.

CORS e credenciais

Em um navegador, uma solicitação de uma origem para outra está sujeita ao CORS, as regras de compartilhamento de recursos entre origens. Se você vir um erro mencionando Access-Control-Allow-Origin, a correção pertence ao servidor, que deve permitir o seu site. No seu JavaScript, a falha aparece apenas como um genérico TypeError, então procure no console do navegador o motivo real. O Node.js não impõe CORS, portanto, uma solicitação que funciona em um script ainda pode falhar no navegador.

Por padrão, os navegadores não enviam cookies em solicitações de origem cruzada. Defina credentials: "include" se precisar deles e certifique-se de que o servidor permita. Nunca coloque chaves de API secretas no JavaScript do navegador, pois qualquer pessoa pode lê-las. Mantenha-os em seu servidor.

Erros comuns

  • Não verificando response.ok. As respostas de erro são tratadas como sucesso.
  • Esquecer o segundo await. response.json() também retorna uma promessa.
  • Esquecer JSON.stringify. Passar um objeto conforme o corpo envia [object Object].
  • Definir Content-Type com FormData. Isso quebra os limites, então deixe-o de fora.
  • Sem tempo limite. Uma solicitação interrompida pode deixar o controle giratório de uma página em execução indefinidamente.
  • Analisando JSON para uma resposta vazia. Um 204 não tem corpo e json() será lançado.

Considerações finais

Buscar é simples quando você se lembra de sua regra principal: uma resposta não é o mesmo que um sucesso. Copie o pequeno auxiliar em seu projeto, adicione um tempo limite e teste seus caminhos de falha. Na próxima etapa, crie uma pequena página que carregue dados de uma API, mostre uma mensagem de erro clara e permita ao usuário cancelar uma pesquisa lenta.

Perguntas frequentes

A busca gera um erro em um 404?

Não. A busca só rejeita quando nenhuma resposta é recebida, como em uma falha de rede. Para erros de HTTP, verifique você mesmo Response.ok ou Response.status.

Como envio JSON com busca?

Defina o método como POST, adicione um cabeçalho Content-Type de application/json e passe os dados por meio de JSON.stringify como corpo.

Por que preciso de duas esperas com busca?

O primeiro é resolvido assim que os cabeçalhos de resposta chegam. O segundo espera que o corpo seja baixado e analisado, o que pode acontecer posteriormente.

Como defino um tempo limite na busca?

Passe sinal: AbortSignal.timeout(5000) nas opções. A solicitação então será rejeitada com um TimeoutError se demorar mais do que esses milissegundos.

A busca está disponível em Node.js?

Sim. O Fetch está disponível globalmente no Node.js 18 e posterior. Versões mais antigas precisam de um pacote, embora as regras CORS se apliquem apenas em navegadores.

Continue aprendendo

Trabalhe com Stack Quora

Precisa de ajuda com testes, WordPress ou SEO?

Ajudamos as equipes a fornecer software melhor e a expandir seus sites. Conte-nos no que você está trabalhando e sugeriremos um próximo passo claro.

Continue lendo

Mais guias sobre testes, IA e desenvolvimento moderno

Gostou deste artigo? Escolha um tópico e vá direto para nossos tutoriais mais recentes.

Inteligência artificial

Explicação das alucinações de IA: por que os modelos de linguagem inventam as coisas e como reduzi-las

Explicação das alucinações de IA: o que são, por que os modelos de linguagem as produzem, tipos comuns, como reduzi-las com aterramento e instruções…

Leia o artigo →
DevOps

Variáveis de ambiente explicadas: arquivos .env, segredos e configuração bem feitos

Variáveis de ambiente explicadas com exemplos de Python que executamos: leitura e configuração, por que cada valor é uma string, arquivos .env, hera…

Leia o artigo →
Desenvolvimento de software

Explicação da limitação de taxa de API: algoritmos, cabeçalhos e tratamento de erros 429

Limitação de taxa de API explicada com uma simulação que executamos: token bucket, janela fixa, janela deslizante, 429 respostas, cabeçalhos de limi…

Leia o artigo →
Automação de testes

Zombando em Python: unittest.mock, patch e os erros que fazem os testes mentirem

Zombaria em Python com unittest.mock, testado: Mock e return_value, side_effect, patch onde um nome é usado, especificação e autospec, zombaria de d…

Leia o artigo →
Teste de software

Cobertura de código explicada: cobertura de linha versus filial e o que 100% realmente significa

Cobertura de código explicada com uma execução cobertura.py real: cobertura de linha, ramal e condição, leitura de um relatório, por que 100% de cob…

Leia o artigo →
Bancos de dados e SQL

DELETE vs TRUNCATE vs DROP em SQL: diferenças, reversão e quando usar cada um

DELETE vs TRUNCATE vs DROP explicado com SQL testado: o que cada um remove, rollback, aciona, redefinição de identidade, velocidade e como PostgreSQ…

Leia o artigo →
Bancos de dados e SQL

Exibições SQL explicadas: crie, use e evite as armadilhas, com exemplos

Visualizações SQL explicadas com consultas que executamos: criação de uma visualização, resultados ao vivo, ocultação de colunas, desempenho, visual…

Leia o artigo →
Desenvolvimento de software

Interface TypeScript vs tipo: diferenças reais, testadas com o compilador

Interface TypeScript versus tipo, verificada com o compilador real: o que ambos podem fazer, o que apenas um pode fazer, mesclagem de declarações, e…

Leia o artigo →
Desenvolvimento de software

Python *args e **kwargs explicados: funções flexíveis com exemplos claros

Python *args e **kwargs explicados com o código que executamos: empacotamento e descompactação, ordem dos parâmetros, argumentos somente de palavras…

Leia o artigo →
Desenvolvimento de software

Funções Python Lambda: sintaxe, usos reais e quando não usá-los

Funções lambda do Python explicadas com o código que executamos: sintaxe, classificação com chave, mapa e filtro, fechamentos, armadilha de ligação …

Leia o artigo →
Inteligência artificial

O que são agentes de IA? Como eles funcionam, com um loop de agente simples que você pode executar

O que são agentes de IA? Um guia simples para o loop do agente, ferramentas, memória e proteções, com um pequeno loop Python que executamos, riscos …

Leia o artigo →
DevOps

Monitoramento versus observabilidade: a verdadeira diferença, com logs, métricas e rastreamentos

Explicação do monitoramento versus observabilidade: falhas conhecidas e desconhecidas, logs, métricas e rastreamentos, um passo a passo do incidente…

Leia o artigo →
DevOps

Docker Volumes vs Bind Mounts: persista os dados do contêiner da maneira certa

Volumes Docker versus montagens de ligação explicadas: por que os dados do contêiner desaparecem, volumes nomeados, montagens de ligação, tmpfs, exe…

Leia o artigo →
Automação de testes

TDD vs BDD: principais diferenças, um recurso criado de ambas as maneiras e quando usar cada um

TDD vs BDD explicado com um recurso de desconto construído em ambos os sentidos: refatoração vermelho-verde com o código que executamos, cenários da…

Leia o artigo →
Teste de software

Teste de aceitação do usuário (UAT): processo, lista de verificação e exemplos reais

Explicação do teste de aceitação do usuário: quem o executa, como ele difere do controle de qualidade, um processo de sete etapas, um modelo de caso…

Leia o artigo →
Bancos de dados e SQL

Valores SQL NULL explicados: IS NULL, COALESCE, NULLIF e as armadilhas a serem evitadas

Valores SQL NULL explicados com consultas que executamos: lógica de três valores, IS NULL, COALESCE, NULLIF, como agregações, junções e classificaçã…

Leia o artigo →
Bancos de dados e SQL

Instrução SQL CASE WHEN: sintaxe, exemplos reais e erros comuns

SQL CASE WHEN explicado com consultas que executamos: formulários simples e pesquisados, ordem de condição, pivôs com SUM, truques COUNT, classifica…

Leia o artigo →
Desenvolvimento de software

O que é JWT? JSON Web Tokens explicados com um exemplo prático

O que é JWT? JSON Web Tokens explicados: as três partes, um token construído e adulterado no código que executamos, JWT vs sessões, armazenamento, t…

Leia o artigo →
Desenvolvimento de software

Loop de eventos JavaScript explicado: pilha de chamadas, microtarefas e temporizadores com exemplos

O loop de eventos JavaScript explicado com o código que executamos: pilha de chamadas, filas de tarefas e microtarefas, por que setTimeout 0 não é i…

Leia o artigo →
Desenvolvimento de software

Geradores Python e rendimento explicado: economize memória com exemplos reais

Geradores Python e rendimento explicados com o código que executamos: como eles pausam e reiniciam, medem economia de memória, pipelines, sequências…

Leia o artigo →
Inteligência artificial

O que são incorporações? Similaridade de vetores e cossenos explicada de forma simples

O que são incorporações? Um guia em linguagem simples para vetores, similaridade de cossenos e pesquisa semântica, com um pequeno exemplo que execut…

Leia o artigo →
DevOps

Implantação azul-verde vs canário: diferenças, compensações e como escolher

Explicação da implantação azul-verde versus canário: como cada um funciona, custo, risco e reversão, agrupamento estável de usuários que testamos, m…

Leia o artigo →
Automação de testes

Testes instáveis: o que os causa e como corrigi-los para sempre

Testes instáveis explicados com demonstrações que executamos: as principais causas, como confirmar e diagnosticar uma, soluções adequadas para tempo…

Leia o artigo →
Teste de software

Teste de carga versus teste de estresse: diferenças, métricas e exemplos k6

Teste de carga versus teste de estresse explicado: o que cada um prova, testes de pico e absorção, as métricas que importam, por que as médias engan…

Leia o artigo →
Teste de software

Caso de teste versus cenário de teste: principais diferenças, exemplos e quando usar cada um

Caso de teste vs cenário de teste explicado: definições claras, uma tabela lado a lado, um recurso de redefinição de senha retirado de cenários para…

Leia o artigo →
Bancos de dados e SQL

Otimização de consultas SQL: leia planos de execução e corrija consultas lentas, com intervalos

Otimização de consulta SQL testada em um milhão de linhas: leia planos de execução, adicione os índices corretos, corrija filtros não sargáveis, use…

Leia o artigo →
Bancos de dados e SQL

SQL UNION vs UNION ALL: diferenças, exemplos e desempenho testado

SQL UNION vs UNION ALL explicado com consultas que executamos: duplicatas, as regras que ambos seguem, um bug de dados real, desempenho medido, INTE…

Leia o artigo →
Desenvolvimento de software

Tutorial da API JavaScript Fetch: GET, POST, tratamento de erros e tempos limite

Um tutorial da API JavaScript Fetch testado em um servidor local: GET e POST, por que 404 não lança, um auxiliar reutilizável, strings de consulta, …

Leia o artigo →
Desenvolvimento de software

Manipulação de arquivos Python: leitura, gravação, CSV, JSON e pathlib com exemplos

Manipulação de arquivos Python explicada com código que executamos: modos abertos, com, leitura de arquivos grandes, CSV, JSON, pathlib, arquivos bi…

Leia o artigo →
Desenvolvimento de software

Git merge vs rebase: diferenças, exemplos e quando usar cada um

Git merge vs rebase explicado com saída real do log, uma tabela comparativa, a regra de ouro do rebase e um fluxo de trabalho seguro para equipes.

Leia o artigo →
Desenvolvimento de software

List comprehension em Python: sintaxe, exemplos e quando evitar

List comprehension em Python explicada: sintaxe, filtros, if-else, laços aninhados, tempos medidos e quando um laço for comum é a melhor escolha.

Leia o artigo →
Bancos de dados e SQL

SQL JOIN explicado com exemplos (Inner, Left, Right, Full)

Entenda os joins SQL passo a passo com tabelas e consultas de exemplo: INNER, LEFT, RIGHT, FULL, CROSS e SELF, além de erros comuns e dicas de desem…

Leia o artigo →