voltar aos artigosweb platform
$cd~/artigos/http-fetch-api-javascript-conversar-servidores
Web Platform
série 33 Conceitos JS·parte 15 de 38

HTTP e Fetch API em JavaScript: Como Conversar com Servidores

14 minVanderlei José Alamino

Uma página moderna raramente vive sozinha. Ela precisa carregar produtos de uma loja, buscar posts de um blog, autenticar usuários, enviar formulários e atualizar notificações em tempo real.

Mas surge uma pergunta fundamental: como o JavaScript consegue se comunicar com servidores?

A resposta está em duas peças importantes:

  • HTTP — o protocolo que define como cliente e servidor conversam
  • Fetch API — a interface moderna do JavaScript para fazer requisições HTTP
snippetJavaScript
// Isso é uma requisição HTTP feita com JavaScript:const response = await fetch('/api/produtos');const produtos = await response.json();

Neste guia da série 33 Conceitos JS — projeto open source criado por Leonardo Maldonado — você vai aprender:

  • O que é HTTP e o padrão Request → Response
  • Métodos HTTP (GET, POST, PUT, PATCH, DELETE) e códigos de status
  • Como a Fetch API funciona com Promises e async/await
  • Por que 404 não lança exceção (e o que fazer a respeito)
  • Como enviar JSON, usar headers e executar requisições em paralelo

Pré-requisitos: Familiaridade com Promises e o event loop. Se você já leu sobre o DOM, verá como fetch encaixa na ponte entre JavaScript e o mundo externo.

http-fetch-api-javascript-conversar-servidores.meta.jsonjson

// metadados do artigo

{
  "tag": "web platform",
  "readTime": "14 min",
  "author": "Vanderlei José Alamino",
  "source": "33jsconcepts.com",
  "series": "33 Conceitos JS",
  "part": {
    "current": 15,
    "total": 38
  }
}
abrir fonte original
http-fetch-api-javascript-conversar-servidores.mdmarkdown

Fonte de referência

Conteúdo adaptado a partir do guia original em inglês.

33jsconcepts.com
01

seção

HTTP: O Protocolo da Web

Antes de falar de fetch(), precisamos entender o HTTP (HyperText Transfer Protocol — Protocolo de Transferência de Hipertexto). É o protocolo que permite a comunicação entre o navegador (cliente) e o servidor.

Quando você acessa uma URL como https://meusite.com/produtos, acontece algo parecido com:

  1. O navegador faz um pedido (request)
  2. O servidor recebe e processa
  3. O servidor envia uma resposta (response)
  4. O navegador usa essa resposta para exibir dados ou atualizar a página

Esse padrão é chamado de Request → Response — a base de toda comunicação na web.

snippettext
Cliente (navegador)       ↓   Pedido (Request)       ↓   Servidor       ↓   Resposta (Response)       ↓Cliente (navegador)
02

seção

Analogia: Um Restaurante

Imagine que você está em um restaurante. Você faz um pedido: "Quero uma pizza." O garçom leva o pedido para a cozinha. A cozinha prepara a comida. Depois o garçom retorna com a resposta.

snippettext
┌─────────────────────────────────────────────────────────────┐│  RESTAURANTE = INTERNET                                     ││                                                             ││  Você (cliente)  ──►  Garçom (HTTP)  ──►  Cozinha (servidor)││                                                             ││  Você (cliente)  ◄──  Garçom (HTTP)  ◄──  Prato pronto      │└─────────────────────────────────────────────────────────────┘

Toda a internet funciona assim: o cliente envia uma mensagem, o servidor processa e devolve uma resposta. No navegador (Chrome, Firefox, Edge), quem normalmente faz esse pedido é o JavaScript:

snippetJavaScript
fetch('/api/produtos');
03

seção

Métodos HTTP

Os métodos HTTP são os verbos da comunicação — eles dizem ao servidor o que você quer fazer com um recurso.

GET — Buscar dados

snippettext
"Me mostre os produtos."
snippetJavaScript
fetch('/api/produtos');// GET é o método padrão quando você não especifica outro

POST — Criar algo novo

snippettext
"Quero cadastrar um usuário."
snippetJavaScript
fetch('/api/usuarios', {  method: 'POST',});

PUT — Substituir completamente

snippettext
"Troque todos os dados deste usuário."
snippetJavaScript
fetch('/api/usuarios/42', {  method: 'PUT',  body: JSON.stringify({ name: 'João', age: 30 }),});

PATCH — Alterar parcialmente

snippettext
"Atualize apenas o nome."
snippetJavaScript
fetch('/api/usuarios/42', {  method: 'PATCH',  body: JSON.stringify({ name: 'Maria' }),});

DELETE — Remover dados

snippettext
"Excluir este produto."
snippetJavaScript
fetch('/api/produtos/99', {  method: 'DELETE',});
MétodoAção típicaIdempotente?
GETLer dadosSim
POSTCriar recursoNão
PUTSubstituir recurso inteiroSim
PATCHAtualizar parcialmenteNão
DELETERemover recursoSim
04

seção

Códigos de Status

Toda resposta HTTP possui um número de status que conta o que aconteceu. Esses números são padronizados e aparecem em toda API REST.

Sucesso e criação

snippettext
200 OK        → Tudo deu certo201 Created   → Um recurso foi criado com sucesso

Erros comuns

snippettext
404 Not Found              → O recurso não existe401 Unauthorized           → Usuário não autenticado500 Internal Server Error    → Algo quebrou no servidor

Regra simples para memorizar

FaixaSignificadoExemplo
2xxSucesso200 OK, 201 Created
3xxRedirecionamento301 Moved Permanently
4xxErro do cliente404 Not Found, 401 Unauthorized
5xxErro do servidor500 Internal Server Error

Dica de entrevista: Erros 4xx significam que você (ou seu código) enviou algo errado. Erros 5xx significam que o servidor falhou — geralmente não é culpa do frontend, mas você ainda precisa tratar na UI.

05

seção

O que é a Fetch API?

A Fetch API é a maneira moderna de fazer requisições HTTP em JavaScript. Ela substituiu o antigo XMLHttpRequest, que era mais complexo e baseado em callbacks aninhados.

Hoje usamos simplesmente:

snippetJavaScript
fetch(url);

A Fetch API está disponível nativamente em todos os navegadores modernos e também no Node.js (a partir da versão 18). Ela retorna Promises, o que combina perfeitamente com async/await.

snippetJavaScript
// Antigo (XMLHttpRequest) — verboso e baseado em callbacksconst xhr = new XMLHttpRequest();xhr.open('GET', '/api/users');xhr.onload = () => console.log(xhr.responseText);xhr.send(); // Moderno (Fetch API) — limpo e baseado em Promisesfetch('/api/users')  .then(response => response.json())  .then(users => console.log(users));
06

seção

Fetch Retorna uma Promise

Isto é fundamental: quando fazemos fetch(), não recebemos os dados imediatamente. Recebemos uma Promise que será resolvida quando a resposta HTTP chegar.

snippetJavaScript
const resposta = fetch('/api/users');console.log(resposta); // Promise { <pending> }

Requisição GET simples

snippetJavaScript
fetch('https://jsonplaceholder.typicode.com/users/1')  .then(response => response.json())  .then(user => {    console.log(user);  });

Entendendo o fluxo — duas Promises

snippettext
fetch()    ↓Promise<Response>     ← 1ª Promise: resposta HTTP chegou    ↓response.json()    ↓Promise<Data>         ← 2ª Promise: corpo convertido em objeto JS    ↓Objeto JavaScript

Existem duas Promises no caminho: a primeira resolve quando os headers e o status chegam; a segunda resolve quando o corpo é parseado (JSON, texto, blob, etc.).

07

seção

Usando async/await

A forma moderna e mais legível de trabalhar com fetch:

snippetJavaScript
async function buscarUsuario() {  const response = await fetch(    'https://jsonplaceholder.typicode.com/users/1'  );   const user = await response.json();   console.log(user);}

O await pausa a função até a Promise resolver, mas não bloqueia o navegador — outras tarefas continuam rodando graças ao event loop.

snippetJavaScript
// Equivalente com .then() — funciona igual, menos legívelfunction buscarUsuario() {  return fetch('https://jsonplaceholder.typicode.com/users/1')    .then(response => response.json())    .then(user => console.log(user));}
08

seção

O Objeto Response

O fetch() não retorna os dados diretamente. Ele retorna um objeto Response com metadados sobre a resposta HTTP:

snippetJavaScript
const response = await fetch(url); console.log(response.status);   // 200console.log(response.ok);       // true (status 200–299)console.log(response.headers);  // Headers objectconsole.log(response.url);      // URL final (após redirects)

response.ok — muito importante

snippetJavaScript
response.ok // true → status entre 200 e 299            // false → qualquer outro status (404, 500, etc.)

Use response.ok para verificar sucesso antes de processar o corpo:

snippetJavaScript
const response = await fetch(url); if (!response.ok) {  throw new Error(`Erro HTTP: ${response.status}`);} const data = await response.json();

Métodos para ler o corpo

MétodoRetornaQuando usar
response.json()Objeto/array JSAPIs REST (padrão)
response.text()StringHTML, CSV, texto puro
response.blob()BlobImagens, arquivos binários
response.arrayBuffer()ArrayBufferDados binários brutos

Atenção: O corpo da resposta só pode ser lido uma vez. Se você chamar response.json() duas vezes, a segunda falhará.

09

seção

O Erro Mais Comum do Fetch

Muitos iniciantes pensam que erros HTTP disparam exceções automaticamente:

snippetJavaScript
try {  await fetch('/api/inexistente'); // retorna 404} catch {  console.log('Erro!'); // ❌ NUNCA entra aqui por causa do 404}

404 NÃO lança exceção. O fetch só rejeita a Promise quando ocorre falha de rede:

  • Ausência de internet
  • DNS inválido
  • Conexão interrompida
  • CORS bloqueado (em alguns casos)

Erros HTTP como 404, 401 e 500 ainda produzem uma Response válida. Por isso verificar response.ok é obrigatório:

snippetJavaScript
async function buscarDados(url) {  const response = await fetch(url);   if (!response.ok) {    throw new Error(`Falha: ${response.status} ${response.statusText}`);  }   return response.json();}
snippetJavaScript
// Padrão completo recomendadotry {  const response = await fetch('/api/produtos');   if (!response.ok) {    throw new Error(`Erro ${response.status}`);  }   const produtos = await response.json();  console.log(produtos);} catch (error) {  // Erros de rede OU erros HTTP que você lançou  console.error('Falha ao buscar:', error.message);}
10

seção

Lendo e Enviando JSON

Quase todas as APIs modernas retornam JSON. O servidor envia:

snippetjson
{  "name": "Vander"}

E o JavaScript converte com response.json():

snippetJavaScript
const response = await fetch(url);const data = await response.json();console.log(data.name); // "Vander"

Enviando dados com POST

snippetJavaScript
await fetch('/api/users', {  method: 'POST',   headers: {    'Content-Type': 'application/json',  },   body: JSON.stringify({    name: 'João',    age: 25,  }),});

O que é JSON.stringify?

Transforma um objeto JavaScript em string JSON — o formato que servidores entendem:

snippetJavaScript
// Objeto JavaScript{ name: 'João' } // JSON.stringify() produz:'{"name":"João"}'

Headers — informações extras

Headers são metadados enviados junto da requisição ou resposta:

snippetJavaScript
headers: {  'Content-Type': 'application/json',  'Authorization': 'Bearer seu-token-aqui',  'Accept-Language': 'pt-BR',}
HeaderFunção
Content-TypeFormato do corpo enviado
AuthorizationToken de autenticação
AcceptFormato de resposta desejado
Cache-ControlRegras de cache
11

seção

Requisições em Paralelo

Executar requisições sequencialmente quando não há dependência entre elas desperdiça tempo:

snippetJavaScript
// ❌ Ruim — a segunda espera a primeira terminarconst usersResponse = await fetch('/users');const postsResponse = await fetch('/posts');

Use Promise.all() para executar em paralelo:

snippetJavaScript
// ✅ Bom — ambas acontecem ao mesmo tempoconst [usersResponse, postsResponse] = await Promise.all([  fetch('/users'),  fetch('/posts'),]); const users = await usersResponse.json();const posts = await postsResponse.json();
snippetJavaScript
// Também funciona com async/await inlineconst [users, posts] = await Promise.all([  fetch('/users').then(r => r.json()),  fetch('/posts').then(r => r.json()),]);

Dica: Se uma requisição falhar, Promise.all rejeita imediatamente. Use Promise.allSettled quando quiser o resultado de todas, mesmo com falhas parciais.

12

seção

Exemplo Real: Carregar Produtos

Juntando tudo em um padrão que você verá em aplicações reais:

snippetJavaScript
async function carregarProdutos() {  try {    const response = await fetch('/api/products');     if (!response.ok) {      throw new Error(`Erro ao carregar: ${response.status}`);    }     const produtos = await response.json();     // Agora use os dados no DOM    produtos.forEach(produto => {      console.log(produto.name, produto.price);    });     return produtos;  } catch (error) {    console.error('Falha na requisição:', error.message);    // Mostrar mensagem de erro na UI  }}

Esse padrão — fetch → verificar ok → json → tratar erro — é a base de qualquer integração frontend com API REST.

13

seção

Relação com o Event Loop

Quando fazemos await fetch(url), o JavaScript não fica parado. A requisição de rede é delegada às Web APIs do navegador, que rodam fora da thread principal.

Quando a resposta chega:

  1. A Promise é resolvida
  2. O callback entra na fila de microtasks
  3. O event loop executa quando a call stack estiver vazia

Por isso o navegador nunca congela enquanto espera a rede — animações, cliques e scroll continuam funcionando.

snippettext
┌──────────────────────────────────────────────────────────────┐│  fetch(url)                                                  ││       ↓                                                      ││  Web API do navegador (rede em background)                   ││       ↓                                                      ││  Promise resolvida → Microtask Queue                         ││       ↓                                                      ││  Event Loop → seu .then() ou await continua                  │└──────────────────────────────────────────────────────────────┘
14

seção

Analogia Final: Correios

Para fixar o conceito:

  • HTTP = sistema dos correios (regras de como enviar e receber)
  • Fetch = funcionário que envia e recebe cartas
  • Request = carta enviada
  • Response = carta recebida

Você envia uma mensagem, continua vivendo normalmente, e dias (ou milissegundos) depois a resposta chega. É exatamente assim que o JavaScript trabalha com requisições — assíncrono, não bloqueante, coordenado pelo event loop.

15

seção

Teste seus conhecimentos

16

seção

Próximos Passos

Agora que você sabe como o JavaScript conversa com servidores via HTTP e Fetch API, o próximo passo na trilha Web Platform é entender Web Workers — como executar código JavaScript em threads separadas para tarefas pesadas sem travar a interface.

Workers combinam perfeitamente com o que você aprendeu: enquanto um Worker processa dados intensivos, a thread principal continua respondendo a cliques, animações e novas requisições fetch.

→ Web Workers — executar tarefas em segundo plano

Fonte de referência: 33jsconcepts.com/concepts/http-fetch ⬀

$ summary --quick

Resumo rápido

  • HTTP segue o padrão Request → Response entre cliente e servidor
  • GET busca dados; POST cria; PUT/PATCH atualizam; DELETE remove
  • Fetch retorna Promises — não os dados finais diretamente
  • response.json() também retorna uma Promise — são duas etapas assíncronas
  • response.ok deve ser verificado — 404 e 500 não lançam exceção automaticamente
  • async/await deixa o código mais legível que callbacks aninhados
  • Promise.all executa várias requisições em paralelo
  • Requisições de rede rodam via Web APIs e se encaixam no event loop

Créditos da série

Este artigo faz parte de uma série de estudos inspirada no projeto 33 Conceitos JS, criado por Leonardo Maldonado. Todo o conteúdo original está disponível em 33jsconcepts.com.