Dominando Requisições HTTP Assíncronas com Axios

O Axios é um cliente HTTP baseado em Promises, popular para fazer requisições assíncronas no navegador e em ambientes Node.js. Ele simplifica a interação com APIs RESTful, oferecendo uma API intuitiva e recursos robustos.

Principais Métodos HTTP para Interação com APIs

Para interagir com recursos em um servidor, o Axios oferece métodos convenientes que correspondem aos verbos HTTP padrão:

  • GET: Utilizado para recuperar dados de um servidor, geralmente para operações de leitura.
  • POST: Empregado para enviar novos dados ao servidor, como o envio de um formulário ou o upload de um arquivo.
  • PUT: Usado para atualizar completamente um recurso existente no servidor.
  • PATCH: Destinado à atualização parcial de um recurso existente.
  • DELETE: Utilizado para remover um recurso específico do servidor.

Visão Geral dos Métodos da API Axios

O Axios fornece uma variedade de métodos para diferentes tipos de requisições:

  • axios.request(config): Método genérico para executar qualquer tipo de requisição com uma configuração abrangente.
  • axios.get(url[, config]): Envia uma requisição GET.
  • axios.delete(url[, config]): Envia uma requisição DELETE.
  • axios.head(url[, config]): Envia uma requisição HEAD.
  • axios.options(url[, config]): Envia uma requisição OPTIONS.
  • axios.post(url[, data[, config]]): Envia uma requisição POST com dados no corpo.
  • axios.put(url[, data[, config]]): Envia uma requisição PUT com dados no corpo.
  • axios.patch(url[, data[, config]]): Envia uma requisição PATCH com dados no corpo.

Opções de Configuração para Requisições Axios

Ao realizar requisições, você pode personalizar o comportamento do Axios por meio de um objeto de configuração detalhado:

{
 // `url` é o endpoint do recurso no servidor
 url: '/recurso',

 // `method` define o método HTTP a ser usado na requisição (padrão: 'get')
 method: 'get',

 // `baseURL` será prefixado à `url` a menos que a `url` seja absoluta.
 // Útil para definir um domínio base para todas as requisições de uma instância.
 baseURL: 'https://minhaapi.com/v1/',

 // `transformRequest` permite modificar os dados da requisição antes de serem enviados ao servidor.
 // Aplicável apenas para métodos 'PUT', 'POST', 'PATCH'.
 transformRequest: [function (dados, cabecalhos) {
   // Exemplo: converter objeto para FormData
   return dados;
 }],

 // `transformResponse` permite modificar os dados da resposta antes de serem passados para then/catch.
 transformResponse: [function (dados) {
   // Exemplo: parsear dados JSON brutos
   return dados;
 }],

 // `headers` são cabeçalhos HTTP personalizados a serem enviados com a requisição.
 headers: {'Content-Type': 'application/json'},

 // `params` são parâmetros de URL que serão anexados à URL da requisição.
 // Deve ser um objeto simples ou uma instância de URLSearchParams.
 params: {
   idUsuario: 123
 },

 // `paramsSerializer` é uma função para serializar o objeto `params`.
 // Por exemplo, para lidar com arrays em parâmetros de URL (e.g., usando 'qs').
 paramsSerializer: function(parametros) {
   // return Qs.stringify(parametros, {arrayFormat: 'brackets'})
   return new URLSearchParams(parametros).toString();
 },

 // `data` são os dados a serem enviados como corpo da requisição.
 // Aplicável apenas para métodos 'PUT', 'POST', 'PATCH'.
 // Pode ser string, objeto simples, ArrayBuffer, FormData, etc.
 data: {
   primeiroNome: 'João',
   ultimoNome: 'Silva'
 },

 // `timeout` especifica o tempo limite da requisição em milissegundos (0 = sem tempo limite).
 // Se a requisição exceder este tempo, ela será abortada.
 timeout: 5000,

 // `withCredentials` indica se cookies de credenciais devem ser enviados em requisições cross-domain.
 withCredentials: false,

 // `adapter` permite personalizar como a requisição é tratada, útil para testes.
 adapter: function (configuracao) {
   /* ... Implementação personalizada ... */
 },

 // `auth` define credenciais para autenticação HTTP básica.
 auth: {
   usuario: 'admin',
   senha: 'senhaSecreta'
 },

 // `responseType` indica o tipo de dado esperado na resposta do servidor.
 // Opções: 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'.
 responseType: 'json',

 // `responseEncoding` indica a codificação a ser usada para decodificar respostas.
 // Ignorado para 'stream' ou requisições no lado do cliente.
 responseEncoding: 'utf8',

 // `xsrfCookieName` é o nome do cookie a ser usado como token XSRF.
 xsrfCookieName: 'XSRF-TOKEN',

 // `xsrfHeaderName` é o nome do cabeçalho HTTP que contém o token XSRF.
 xsrfHeaderName: 'X-XSRF-TOKEN',

 // `onUploadProgress` permite lidar com eventos de progresso de upload.
 onUploadProgress: function (eventoProgresso) {
   // Lógica para atualizar a barra de progresso
 },

 // `onDownloadProgress` permite lidar com eventos de progresso de download.
 onDownloadProgress: function (eventoProgresso) {
   // Lógica para atualizar a barra de progresso
 },

 // `maxContentLength` define o tamanho máximo permitido para o conteúdo da resposta.
 maxContentLength: 2000,

 // `validateStatus` define quais códigos de status HTTP devem resolver (sucesso) ou rejeitar (erro) a Promise.
 // Se retornar `true`, a Promise é resolvida; caso contrário, é rejeitada.
 validateStatus: function (status) {
   return status >= 200 && status < 300; // Padrão: aceita status 2xx
 },

 // `maxRedirects` define o número máximo de redirecionamentos a seguir em Node.js.
 maxRedirects: 5,

 // `socketPath` define um Socket UNIX a ser usado em Node.js.
 socketPath: null,

 // `httpAgent` e `httpsAgent` definem agentes personalizados para requisições HTTP e HTTPS em Node.js.
 // Exemplo: new http.Agent({ keepAlive: true }) para manter conexões.
 httpAgent: null,
 httpsAgent: null,

 // `proxy` configura um servidor proxy para a requisição.
 proxy: {
   host: '127.0.0.1',
   port: 9000,
   auth: {
     usuario: 'proxyUser',
     senha: 'proxyPassword'
   }
 },

 // `cancelToken` especifica um token para cancelar a requisição.
 cancelToken: new axios.CancelToken(function (cancelar) { })
}

Estrutura do Objeto de Resposta

Quando uma requisição é bem-sucedida, o Axios retorna um objeto Promise que, ao ser resolvido, oferece acesso a um objeto de resposta com as seguintes propriedades:

{
 // `data` são os dados fornecidos pelo servidor
 dados: {},

 // `status` é o código de status HTTP da resposta do servidor
 status: 200,

 // `statusText` é a mensagem de status HTTP da resposta do servidor
 statusTexto: 'OK',

 // `headers` são os cabeçalhos da resposta do servidor
 cabecalhos: {},

 // `config` é o objeto de configuração utilizado para a requisição
 config: {},

 // `request` é a instância da requisição que gerou esta resposta
 // (XMLHttpRequest no navegador, ClientRequest no Node.js)
 requisicao: {}
}

Você pode acessar essas propriedades no callback .then():

axios.get('/api/usuarios/101')
 .then(function(resposta) {
   console.log('Dados recebidos:', resposta.dados);
   console.log('Status HTTP:', resposta.status);
   console.log('Mensagem de Status:', resposta.statusTexto);
   console.log('Cabeçalhos da Resposta:', resposta.cabecalhos);
   console.log('Configuração da Requisição:', resposta.config);
 })
 .catch(function(erro) {
   console.error('Ocorreu um erro na requisição:', erro);
 });

Exemplos Práticos: Requisições GET

Exemplo 1: Obtendo e Renderizando Dados em uma Lista

Este exemplo demonstra como buscar dados e exibi-los em uma lista HTML. Assumimos um framework reativo como Vue.js ou React, mas a lógica do Axios é agnóstica.

<template>
 <div>
   <button @click="carregarProdutos">Buscar Produtos</button>
   <ul v-if="listaProdutos.length">
     <li v-for="produto in listaProdutos" :key="produto.id">
       {{ produto.id }} - {{ produto.nome }} (Fabricante: {{ produto.fabricante }})
     </li>
   </ul>
   <p v-else>Nenhum produto encontrado.</p>
 </div>
</template>

<script>
import axios from 'axios';

export default {
 data() {
   return {
     listaProdutos: []
   };
 },
 methods: {
   carregarProdutos() {
     axios.get('/api/produtos')
       .then(response => {
         console.log('Resposta completa:', response);
         this.listaProdutos = response.data; // 'data' contém os dados reais da resposta
       })
       .catch(error => {
         console.error('Falha ao carregar produtos:', error);
       });
   }
 }
};
</script>

Exemplo 2: Requisições GET com Parâmetros de Query

Para enviar parâmetros na URL (http://localhost:8080/api/itens?id=1), você pode usar o objeto params ou construir a URL diretamente:

// Usando o objeto 'params' na configuração
this.$axios.get('/api/itens', {
   params: {
       itemId: 1
   }
})
.then(resposta => {
   console.log(resposta.data);
})
.catch(erro => {
   console.error('Erro na requisição:', erro);
});

// Ou construindo a URL com parâmetros manualmente (menos recomendado para múltiplos parâmetros)
this.$axios.get('/api/itens?itemId=1')
.then(resposta => {
   console.log(resposta.data);
})
.catch(erro => {
   console.error('Erro na requisição:', erro);
});

// Utilizando a sintaxe completa com o método 'request'
this.$axios({
   method: 'get',
   url: '/api/itens',
   params: {
       itemId: 1
   }
})
.then(resposta => {
   console.log(resposta.data);
})
.catch(erro => {
   console.error('Erro na requisição:', erro);
});

Exemplos Práticos: Requisições POST

Exemplo 1: Adicionando um Novo Recurso

Para enviar dados no corpo da requisição POST:

data() {
 return {
   novoItem: {
     titulo: '',
     descricao: ''
   }
 };
},
methods: {
 adicionarNovoItem() {
   axios.post("/api/posts", this.novoItem)
     .then(response => {
       console.log("Item criado com sucesso:", response.data);
       this.carregarItens(); // Atualiza a lista após a criação
     })
     .catch(error => {
       console.error("Erro ao criar item:", error);
     });
 }
}

Exemplo 2: Requisição POST Direta

// Envio de dados diretamente como objeto no corpo da requisição
axios.post('/api/usuarios', {
   nome: 'Alice',
   idade: 30
})
.then(resposta => {
   console.log('Usuário registrado:', resposta.data);
})
.catch(erro => {
   console.error('Erro no registro:', erro);
});

// Usando a sintaxe completa com o método 'request'
this.$axios({
   method: 'post',
   url: '/api/usuarios',
   data: {
       nome: 'Bob',
       idade: 25
   }
})
.then(resposta => {
   console.log('Usuário registrado:', resposta.data);
})
.catch(erro => {
   console.error('Erro no registro:', erro);
});

Requisições Concorrentes

O Axios permite executar múltiplas requisições em paralelo e esperar por todas elas usando axios.all() e axios.spread():

function obterInformacoesCliente() {
 return axios.get('/api/clientes/123');
}

function obterHistoricoCompras() {
 return axios.get('/api/clientes/123/compras');
}

axios.all([obterInformacoesCliente(), obterHistoricoCompras()])
 .then(axios.spread(function (infoCliente, historico) {
   // Ambos os dados (infoCliente e historico) estão agora disponíveis
   console.log('Detalhes do Cliente:', infoCliente.data);
   console.log('Histórico de Compras:', historico.data);
 }))
 .catch(erro => {
   console.error('Erro em uma das requisições concorrentes:', erro);
 });

Modernizando com Async/Await

async e await oferecem uma maneira mais síncrona e legível de escrever código assíncrono. Uma função marcada como async sempre retorna uma Promise. O operador await pode ser usado dentro de funções async para pausar a execução até que uma Promise seja resolvida ou rejeitada, tornando o fluxo de controle mais linear.

async function adicionarNovoProdutoAsync() {
 try {
   const resposta = await axios.post("/api/produtos", this.dadosProduto);
   console.log("Produto adicionado:", resposta.data);
   await this.atualizarListaProdutos(); // Chama outra função assíncrona
   console.log("Lista de produtos atualizada.");
 } catch (erro) {
   console.error("Erro ao adicionar produto:", erro);
 }
}

Exemplos Práticos: PUT, PATCH e DELETE

Requisições PUT (Atualização Completa)

this.$axios.put('/api/recursos/5', {
   novoCampo: 'valorAtualizado',
   outroCampo: 'novoValor'
})
.then(resposta => {
   console.log('Recurso atualizado completamente:', resposta.data);
})
.catch(erro => {
   console.error('Erro ao atualizar recurso (PUT):', erro);
});

Requisições PATCH (Atualização Parcial)

this.$axios.patch('/api/recursos/5', {
   apenasEsteCampo: 'valorAlterado'
})
.then(resposta => {
   console.log('Recurso atualizado parcialmente:', resposta.data);
})
.catch(erro => {
   console.error('Erro ao atualizar recurso (PATCH):', erro);
});

Requisições DELETE (Remoção de Dados)

Para requisições DELETE, você pode enviar parâmetros na URL (via params) ou no corpo da requisição (via data).

Deletar com Parâmetros na URL (Query String)

// Usando o objeto 'params' para anexar à URL
axios.delete("/api/registros", {
   params: {
       registroId: 15
   }
})
.then(response => {
   console.log('Registro deletado via URL params:', response);
})
.catch(error => {
   console.error('Erro ao deletar registro (URL params):', error);
});

// Ou diretamente na URL (string de query)
axios.delete("/api/registros?registroId=16")
.then(response => {
   console.log('Registro deletado via URL direta:', response);
})
.catch(error => {
   console.error('Erro ao deletar registro (URL direta):', error);
});

// Sintaxe completa com método 'request'
let paramsParaDeletar = { idParaRemover: 17 };
axios({
   method: 'delete',
   url: '/api/registros',
   params: paramsParaDeletar
})
.then(response => {
   console.log('Registro deletado via config params:', response);
})
.catch(error => {
   console.error('Erro ao deletar registro (config params):', error);
});

Deletar com Dados no Corpo da Requisição (Body)

// Usando o objeto 'data' para enviar no corpo da requisição
axios.delete("/api/registros", {
   data: {
       identificadorUnico: 20
   }
})
.then(response => {
   console.log('Registro deletado via corpo da requisição:', response);
})
.catch(error => {
   console.error('Erro ao deletar registro (body):', error);
});

// Sintaxe completa com método 'request'
let dadosParaDeletar = { chaveDeleta: 21 };
axios({
   method: 'delete',
   url: '/api/registros',
   data: dadosParaDeletar
})
.then(response => {
   console.log('Registro deletado via config data:', response);
})
.catch(error => {
   console.error('Erro ao deletar registro (config data):', error);
});

Criação e Configuração de Instâncias Axios

Criar instâncias do Axios permite configurar diferentes comportamentos para diferentes partes da sua aplicação, evitando conflitos e repetindo configurações comuns. Propriedades como baseURL e timeout são ideais para instâncias.

  • baseURL: O URL base para todas as requisições desta instância (String).
  • timeout: Duração máxima da requisição em ms (padrão: 0, sem limite) (Number).
  • url: Caminho específico da requisição (String).
  • method: Método HTTP (get, post, put, etc.) (String).
  • headers: Objeto com cabeçalhos HTTP personalizados (Object).
  • params: Parâmetros de query para a URL (Object).
  • data: Dados a serem enviados no corpo da requisição (Object).
const apiClientes = axios.create({
 baseURL: 'https://api.meusclientes.com/v1/',
 timeout: 5000,
 headers: {'X-Api-Key': 'abc123def'}
});

// Exemplo de uso
apiClientes.get('/lista-clientes')
 .then(response => console.log(response.data))
 .catch(error => console.error(error));

Cenários com Múltiplas Instâncias

Se você tem diferentes domínios de API ou requisitos de timeout, pode criar múltiplas instâncias:

<script>
import axios from "axios";

export default {
 name: "ComponenteRequisição",
 created() {
   // Instância para a API de produtos (timeout padrão)
   let instanciaProdutos = axios.create({
     baseURL: "http://localhost:3000/api",
     timeout: 3000,
   });
   instanciaProdutos.get("/produtos").then((res) => {
     console.log("Dados de produtos:", res.data);
   });

   // Instância para a API de usuários (timeout maior)
   let instanciaUsuarios = axios.create({
     baseURL: "http://localhost:3001/api",
     timeout: 10000,
   });
   instanciaUsuarios.get("/usuarios").then((res) => {
     console.log("Dados de usuários:", res.data);
   });
 },
};
</script>

Você também pode definir configurações padrão diretamente em uma instância:

let minhaApiConfig = axios.create({
 baseURL: "https://minhaempresa.com/api/",
 timeout: 7000,
 headers: {
   'Authorization': 'Bearer meuToken',
   'Post-Type': 'application/json;charset=UTF-8'
 },
 params: { versao: '2.0' }, // Parâmetros de query padrão
 data: { origem: 'web' },   // Dados padrão para POST/PUT/PATCH
});

Prioridade das Configurações

As configurações do Axios são mescladas com uma ordem de prioridade específica:

  1. Configuração de Requisição: Parâmetros passados diretamente na chamada do método (axios.get('/url', { timeout: 1000 })).
  2. Configuração da Instância: Configurações definidas ao criar uma instância (axios.create({ timeout: 2500 })).
  3. Configuração Global: Valores padrão do próprio Axios (axios.defaults.timeout = 0).
// Configuração global padrão (timeout 0)
axios.defaults.timeout = 0; // Desativa timeout global

// Criamos uma instância, sobrescrevendo o timeout global para 2.5 segundos
var apiComTempoLimite = axios.create();
apiComTempoLimite.defaults.timeout = 2500;

// Para uma requisição específica que pode demorar mais, sobrescrevemos o timeout da instância para 5 segundos
apiComTempoLimite.get('/recurso-demorado', {
 timeout: 5000
})
.then(response => console.log('Resposta do recurso demorado:', response.data))
.catch(error => console.error('Erro no recurso demorado:', error));

// Para outras requisições da instância, o timeout de 2.5 segundos será aplicado
apiComTempoLimite.get('/recurso-padrao')
.then(response => console.log('Resposta do recurso padrão:', response.data))
.catch(error => console.error('Erro no recurso padrão:', error));

Interceptors (Interceptadores)

Interceptors permitem que você intercepte requisições ou respostas antes que sejam manipuladas por .then() ou .catch(). Isso é útil para adicionar autenticação, logs, manipulação de erros, etc.

Interceptador de Requisição

Executado antes que uma requisição seja enviada:

this.$axios.interceptors.request.use(config => {
   // Exemplo: Adicionar um token de autorização a cada requisição
   const token = localStorage.getItem('authToken');
   if (token) {
       config.headers.Authorization = `Bearer ${token}`;
   }
   console.log('Requisição interceptada:', config.url);
   return config; // Sempre retorne a configuração modificada
}, error => {
   // Lidar com erros antes que a requisição seja enviada (ex: problemas de configuração)
   console.error('Erro no interceptador de requisição:', error);
   return Promise.reject(error); // Rejeita a Promise para que o erro seja tratado
});

Interceptador de Resposta

Executado após o recebimento de uma resposta, antes de ser entregue aos callbacks .then() ou .catch():

axios.interceptors.response.use(response => {
   // Exemplo: Simplificar a resposta retornando apenas os dados
   console.log('Resposta interceptada:', response.config.url);
   return response.data; // Retorna apenas os dados, em vez do objeto de resposta completo
}, error => {
   // Lidar com erros de resposta (ex: status 401, 500)
   console.error('Erro no interceptador de resposta:', error);
   if (error.response && error.response.status === 401) {
       // Lógica para redirecionar para login, por exemplo
       console.log('Sessão expirada. Redirecionando para login...');
   }
   return Promise.reject(error);
});

Interceptadores para Instâncias Personalizadas

Você pode adicionar interceptadores a instâncias específicas do Axios:

let apiAutenticada = axios.create({
   baseURL: 'https://api.segura.com'
});

apiAutenticada.interceptors.request.use(config => {
   config.headers.MeuHeader = 'ValorCustomizado';
   return config;
});

Reomvendo Interceptadores

Para remover um interceptador, você deve armazenar a referência dele ao criá-lo e depois usar eject:

const idInterceptador = this.$axios.interceptors.request.use(config => {
   config.headers.Log = 'Requisição Logada';
   return config;
});

// Para remover
this.$axios.interceptors.request.eject(idInterceptador);
console.log('Interceptador de requisição removido.');

Tratamento de Erros

Tanto erros de requisição (antes de serem enviadas) quanto erros de resposta (após o servidor responder) são capturados pelo bloco .catch() da Promise, ou pelos interceptadores de erro.

import axios from "axios";

// Interceptador de Requisição para tratar erros antes do envio
axios.interceptors.request.use(
 config => {
   console.log('Requisição enviada:', config.url);
   return config;
 },
 error => {
   console.error('Erro na configuração da requisição:', error);
   // Exibir um toast de erro ou mensagem para o usuário
   return Promise.reject(error);
 }
);

// Interceptador de Resposta para tratar erros após a resposta do servidor
axios.interceptors.response.use(
 response => {
   console.log('Resposta recebida:', response.config.url);
   return response;
 },
 error => {
   console.error('Erro na resposta da API:', error.response);
   // Lógica para exibir mensagens de erro baseadas no status HTTP
   if (error.response && error.response.status === 404) {
     alert('Recurso não encontrado!');
   } else if (error.response && error.response.status === 500) {
     alert('Erro interno do servidor!');
   }
   return Promise.reject(error);
 }
);

// Exemplo de requisição com tratamento de erro global e específico
axios.get("/api/recursos-inexistentes")
 .then(res => {
   console.log('Requisição bem-sucedida:', res.data);
 })
 .catch(err => {
   console.error('Erro tratado no catch da requisição:', err.message);
   // Lógica de tratamento de erro específica para esta requisição
 });

Configurando Validação de Status HTTP

Você pode personalizar quais códigos de status HTTP são considerados erros. Por padrão, o Axios rejeita Promises para status >= 300.

axios.get('/api/status/exemplo', {
 validateStatus: function (status) {
   return status >= 200 && status < 400; // Resolve a Promise para status 2xx e 3xx, rejeita para 4xx ou 5xx
 }
})
.then(response => console.log('Requisição bem-sucedida (status 2xx ou 3xx):', response.data))
.catch(error => console.error('Requisição com erro (status 4xx ou 5xx):', error));

Cancelamento de Requisições

É possível cancelar requisições em andamento, o que é útil em cenários como buscas com digitação rápida (para evitar resultados obsoletos) ou quando um componente é desmontado antes da conclusão da requisição.

<template>
 <div>
   <p>Exemplo de Cancelamento de Requisição</p>
   <button @click="iniciarBusca">Iniciar Busca Demorada</button>
   <button @click="cancelarBusca">Cancelar Busca</button>
   <p v-if="resultado">Resultado: {{ resultado }}</p>
   <p v-if="erroCancelamento">Erro de Cancelamento: {{ erroCancelamento }}</p>
 </div>
</template>

<script>
import axios from "axios";

export default {
 name: "CancelamentoRequisição",
 data() {
   return {
     cancelSource: null,
     resultado: null,
     erroCancelamento: null
   };
 },
 methods: {
   iniciarBusca() {
     // Cria um novo token de cancelamento
     this.cancelSource = axios.CancelToken.source();
     this.resultado = null;
     this.erroCancelamento = null;

     axios.get("/api/recurso-pesado", {
         cancelToken: this.cancelSource.token,
       })
       .then((res) => {
         this.resultado = res.data;
         console.log("Requisição concluída:", res.data);
       })
       .catch((err) => {
         if (axios.isCancel(err)) {
           this.erroCancelamento = err.message;
           console.log("Requisição cancelada:", err.message);
         } else {
           console.error("Erro na requisição:", err);
         }
       })
       .finally(() => {
         this.cancelSource = null; // Limpa o token após a requisição/cancelamento
       });
   },
   cancelarBusca() {
     if (this.cancelSource) {
       this.cancelSource.cancel("Operação de busca cancelada pelo usuário.");
     }
   }
 }
};
</script>

Encapsulamento de Instâncias Axios

Encapsular o Axios em um módulo ou função facilita a gestão de configurações, interceptadores e erros. Isso promove reutilização de código, manutenibilidade e flexibilidade, caso seja necessário trocar a biblioteca HTTP no futuro.

// services/httpService.js
import axios from 'axios';

export function criarClienteHTTP(configuracaoInicial) {
 // 1. Cria uma nova instância Axios com configurações base
 const instancia = axios.create({
   baseURL: configuracaoInicial.baseURL || "http://localhost:8080/api",
   timeout: configuracaoInicial.timeout || 8000,
   headers: {
     'Content-Type': 'application/json',
     ...configuracaoInicial.headers // Mescla cabeçalhos adicionais
   }
 });

 // 2. Adiciona interceptadores de requisição
 instancia.interceptors.request.use(
   config => {
     // Exemplo: Adicionar token de autenticação, se disponível
     const token = localStorage.getItem('jwtToken');
     if (token) {
       config.headers.Authorization = `Bearer ${token}`;
     }
     // Exemplo: Mostrar um indicador de carregamento
     // mostrarSpinnerGlobal();
     return config;
   },
   error => {
     // Lidar com erros na fase de envio da requisição
     console.error("Erro no interceptador de requisição:", error);
     // ocultarSpinnerGlobal();
     return Promise.reject(error);
   }
 );

 // 3. Adiciona interceptadores de resposta
 instancia.interceptors.response.use(
   response => {
     // Exemplo: Ocultar o indicador de carregamento
     // ocultarSpinnerGlobal();
     return response; // Retorne a resposta completa ou apenas os dados (response.data)
   },
   error => {
     // Lidar com erros de resposta HTTP
     console.error("Erro no interceptador de resposta:", error.response);
     // ocultarSpinnerGlobal();

     if (error.response) {
       const { status, data } = error.response;
       if (status === 401) {
         console.log("Sessão expirada ou não autorizada. Redirecionando...");
         // window.location.href = '/login';
       } else if (status === 404) {
         console.log("Recurso não encontrado.");
       } else {
         console.log(`Erro no servidor: ${status} - ${data.message || 'Erro desconhecido'}`);
       }
     } else if (error.request) {
       // A requisição foi feita, mas não houve resposta (rede offline, CORS, etc.)
       console.error("Nenhuma resposta recebida do servidor.");
     } else {
       // Algo aconteceu na configuração da requisição que disparou um erro
       console.error("Erro ao configurar requisição:", error.message);
     }
     return Promise.reject(error);
   }
 );

 // 4. Retorna a instância configurada
 return instancia;
}

// Exemplo de uso em outro arquivo:
// import { criarClienteHTTP } from './services/httpService';
// const clienteAPI = criarClienteHTTP({ baseURL: 'https://minhaapi.com/v1' });
// clienteAPI.get('/usuarios').then(res => console.log(res.data));

Este padrão garante que todas as requisições feitas através de instancia herdem as configurações e interceptadores definidos, enquanto permite flexibilidade para ajustes específicos por chamada.

Gerenciamento de Tokens de Autenticação

Ao lidar com rotas protegidas por autenticação (como JWT), o interceptador de requisição é o local ideal para adicionar o token ao cabeçalho Authorization.

// Exemplo de instância para rotas que exigem autenticação
let clienteAutenticado = axios.create({});
clienteAutenticado.interceptors.request.use(config => {
   const token = obterTokenDeAutenticacao(); // Função para buscar o token (ex: localStorage)
   if (token) {
       config.headers.Authorization = `Bearer ${token}`;
   }
   return config;
}, error => {
   return Promise.reject(error);
});

// Para rotas públicas, use outra instância ou o Axios padrão sem este interceptador.
let clientePublico = axios.create({});

Integração com Animações de Carregamento (Loading)

Interceptors também são excelentes para exibir e ocultar indicadores de carregamento durante as requisições.

let clienteComLoading = axios.create({});

// Interceptador de Requisição: mostra o spinner
clienteComLoading.interceptors.request.use(config => {
   mostrarSpinnerDeCarregamento(); // Função que exibe seu spinner
   return config;
}, error => {
   ocultarSpinnerDeCarregamento(); // Garante que o spinner seja ocultado mesmo em erro pré-envio
   return Promise.reject(error);
});

// Interceptador de Resposta: oculta o spinner
clienteComLoading.interceptors.response.use(response => {
   ocultarSpinnerDeCarregamento(); // Oculta o spinner ao receber uma resposta
   return response;
}, error => {
   ocultarSpinnerDeCarregamento(); // Oculta o spinner em caso de erro na resposta
   return Promise.reject(error);
});

function mostrarSpinnerDeCarregamento() {
 console.log("Mostrando spinner de carregamento...");
 // Lógica real para exibir o spinner no DOM
}

function ocultarSpinnerDeCarregamento() {
 console.log("Ocultando spinner de carregamento...");
 // Lógica real para ocultar o spinner no DOM
}

Tags: Axios HTTP javascript RequisiçõesAssíncronas RESTfulAPI

Publicado em 7-5 08:43