Menu

Fetch API em JavaScript: requisições, JSON e erros

Aprenda a usar a Fetch API do JavaScript na prática: requisições GET e POST, parse de JSON, tratamento de erros e como cancelar requisições com AbortController.

Fetch: um cliente HTTP baseado em Promises

A fetch já vem embutida nos navegadores e nas versões modernas do Node. Você passa uma URL, e ela devolve uma Promise que resolve para um objeto Response. No fundo, é essa a API inteira:

index.js
Output
Click Run to see the output here.

Dois .then em sequência porque existem duas etapas assíncronas: primeiro chegam os cabeçalhos da resposta (é isso que a primeira promise entrega), e só depois o corpo é lido e convertido (response.json() também é uma promise). O corpo só é baixado quando você pede.

O mesmo fluxo com async/await fica parecendo código comum, lido de cima para baixo:

index.js
Output
Click Run to see the output here.

Dois await, dois pontos de suspensão. O mesmo trabalho, só que bem mais fácil de ler de cima pra baixo.

O objeto Response

O que a fetch devolve não é o corpo da resposta — é um objeto Response, que traz os metadados e os métodos para você ler esse corpo em diferentes formatos:

index.js
Output
Click Run to see the output here.

Você pode ler o corpo da resposta usando .json(), .text(), .blob(), .arrayBuffer() ou .formData(). Cada um desses métodos retorna uma promise. E tem um detalhe importante: o corpo só pode ser lido uma vez — se você chamar .json() duas vezes na mesma resposta, a segunda chamada vai estourar um erro.

A maior pegadinha: erros HTTP não rejeitam a promise

Essa aqui confunde praticamente todo mundo que está começando com o fetch. Uma resposta 404 ou 500 não é uma rejeição. A promise resolve normalmente, só que com response.ok === false. O fetch só rejeita quando a requisição em si não conseguiu completar — falha de DNS, sem conexão de rede ou bloqueio por CORS.

Na prática, isso significa que um fetch ingênuo vai aceitar numa boa uma página de erro e só vai quebrar depois, na hora do .json():

index.js
Output
Click Run to see the output here.

A solução é verificar response.ok manualmente e lançar um erro quando o servidor retornar um status de erro:

index.js
Output
Click Run to see the output here.

Acostume-se a escrever esse bloco if (!response.ok). Ele merece um lugar em todo wrapper de fetch que você criar.

Fazendo uma requisição POST com fetch

GET é o método padrão. Para qualquer outro verbo HTTP, basta passar um segundo argumento — um objeto de opções:

index.js
Output
Click Run to see the output here.

Três coisas que vale a pena destacar:

  • method tem como padrão "GET". Defina explicitamente quando for POST, PUT, DELETE ou PATCH.
  • body aceita uma string (ou FormData, Blob, etc.) — o fetch não serializa objetos automaticamente para você. O JSON.stringify(...) é responsabilidade sua.
  • O header Content-Type diz ao servidor como interpretar o corpo da requisição. Se esquecer, a maioria dos servidores vai tratar o body como texto puro.

Headers, query strings e outras opções do fetch

Os headers podem ser um objeto comum (ou uma instância de Headers). Já a query string você monta na mão, normalmente com URLSearchParams:

index.js
Output
Click Run to see the output here.

URLSearchParams cuida da codificação pra você — espaços, &, unicode — assim você não acaba com URLs quebradas quando a entrada tem caracteres que precisam ser escapados.

Outras opções que você vai ver em código real: credentials: "include" pra enviar cookies em requisições cross-origin, cache: "no-store" pra ignorar o cache HTTP, e mode: "cors" (que normalmente é o padrão) pra controlar o comportamento de CORS.

Cancelando uma requisição com AbortController

Às vezes você precisa desistir da requisição — o usuário digitou uma nova busca, ou a chamada está demorando demais. É aí que entra o AbortController:

index.js
Output
Click Run to see the output here.

controller.abort() faz com que a promise do fetch seja rejeitada com uma DOMException cujo name é "AbortError". Já o bloco finally limpa o timeout para que uma requisição bem-sucedida não deixe um timer pendurado por aí.

Esse padrão — fetch com timeout e limpeza — vale a pena ser encapsulado em um helper para reutilizar em todo lugar.

Um wrapper reutilizável

Juntando tudo, dá pra montar um pequeno helper que cuida do boilerplate de uma vez só:

index.js
Output
Click Run to see the output here.

Um único lugar pra ajustar headers, um único lugar pra tratar erros, um único lugar pra lidar com respostas vazias. Todo app minimamente sério acaba chegando em algo parecido com isso.

A seguir: tratamento de erros em código assíncrono

O fetch é um dos pontos onde erros assíncronos mais aparecem, e a verificação do response.ok é só uma das peças do quebra-cabeça. A próxima página fala sobre tratamento de erros em promises e async/await — pra onde os erros vão, como capturá-los e as armadilhas que deixam eles passarem despercebidos.

Perguntas frequentes

Como usar o fetch no JavaScript?

Basta chamar fetch(url) passando a URL desejada. Ele retorna uma Promise que resolve em um objeto Response. Para ler o corpo como JSON, chame response.json() (que também é uma promise). Com async/await fica assim: const res = await fetch(url); const data = await res.json();.

Como fazer uma requisição POST com fetch?

Passe um segundo argumento no fetch com method: 'POST', um objeto headers (normalmente 'Content-Type': 'application/json') e o body. Lembre de converter objetos em string com JSON.stringify(...) — o fetch não serializa o corpo automaticamente pra você.

Por que o fetch não dispara erro em status 404 ou 500?

O fetch só rejeita a promise em falhas de rede — erros de DNS, sem conexão, bloqueio de CORS. Para ele, uma resposta HTTP com status de erro ainda é uma resposta válida. Cabe a você checar response.ok (true entre 200 e 299) ou response.status e lançar um erro manualmente quando o servidor retornar algo inesperado.

Dá para cancelar uma requisição fetch?

Dá sim, usando o AbortController. Você cria uma instância, passa o signal dela no objeto de opções do fetch e chama controller.abort() quando quiser cancelar. A promise do fetch vai rejeitar com um AbortError, que você trata normalmente no catch.

Aprenda a programar com o Coddy

COMEÇAR