react-axios-interceptores

Axios e Interceptores en React

  • 5 min

En los articulos anteriores aprendimos a pedir datos con fetch. Funciona, es nativo y es estándar.

Pero como vimos, tiene sus asperezas: hay que convertir el JSON manualmente, no gestiona los errores HTTP automáticamente y nos obliga a repetir cabeceras (headers) constantemente.

Cuando construimos aplicaciones grandes, a veces necesitamos una capa más cómoda. Una opción muy habitual (aunque no obligatorioa) es Axios.

Axios es una librería basada en promesas que hace lo mismo que fetch, pero con una API más cómoda y funcionalidades avanzadas que nos ahorran bastante código repetido.

Los fetch nativos han mejorado muchisimo los últimos años, y continuan haciéndolo. De forma que Axios ya no es tan imprescindible con era.

Aún así, sigue siendo una opción muy usada, y la encontraréis seguro. Así que vamos a verla.

¿Por qué Axios?

Antes de instalar nada, entendamos las mejoras inmediatas frente a fetch:

  1. Transformación automática de JSON: Adiós al response.json(). Axios te devuelve los datos directamente.
  2. Manejo de errores sensato: Si la API devuelve un 404 o un 500, Axios lanza una excepción automáticamente (entra en el .catch). Con fetch teníamos que comprobar response.ok a mano.
  3. Instancias e Interceptores: El motivo principal por el que mucha gente lo usa.

Instalación

Instalar Axios es muy sencillo. Se instala simplemente como cualquier otro paquete normal, no tiene más misterio.

npm install axios
Copied!

Creando una Instancia (Singleton)

Un error habitual es importar axios directamente en cada componente (import axios from 'axios').

Si hacéis eso, tendréis que escribir la URL base (https://api.midominio.com) en cada petición. Si mañana la API cambia de dirección, tendréis que editar 50 archivos.

Para evitar esa repetición, crearemos una Instancia Centralizada.

Cread un archivo en src/api/axios.js (o src/lib/axios.js):

import axios from 'axios';

// Creamos una instancia con configuración base
const api = axios.create({
  baseURL: 'https://api.tuweb.com/v1',
  timeout: 5000, // Si tarda más de 5s, aborta
  headers: {
    'Content-Type': 'application/json'
  }
});

export default api;
Copied!

Ahora, en vuestros componentes, importaréis este objeto api en lugar de la librería axios.

// En un componente cualquiera
import api from '../api/axios';

// La petición será a: https://api.tuweb.com/v1/usuarios
const response = await api.get('/usuarios'); 
Copied!

Interceptores

Los Interceptores son funciones que se ejecutan antes de que la petición salga de nuestra app, o antes de que la respuesta llegue a nuestro componente.

Son como aduanas o peajes por donde pasa todo el tráfico HTTP.

Interceptor de Request

El caso de uso número uno es la Autenticación. Si tenemos un token de usuario (JWT) guardado en el LocalStorage o en un Store de Zustand, queremos enviarlo en todas las peticiones privadas.

En lugar de añadir el header Authorization manualmente en cada llamada, dejamos que el interceptor lo inyecte.

// src/api/axios.js (continuación)

api.interceptors.request.use(
  (config) => {
    // 1. Buscamos el token (en localStorage o donde lo tengáis)
    const token = localStorage.getItem('token');
    
    // 2. Si existe, lo inyectamos en la cabecera
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    
    return config; // Importante devolver la config modificada
  },
  (error) => {
    return Promise.reject(error);
  }
);
Copied!

Ahora cualquier llamada api.get('/perfil') llevará el token automáticamente.

Interceptor de Response

El caso de uso principal aquí es el Manejo Global de Errores. ¿Qué pasa si el token ha caducado (Error 401)? No queremos comprobar el error 401 en cada componente.

Queremos que, si ocurre un 401 en cualquier sitio, la app redirija al usuario al Login automáticamente.

api.interceptors.response.use(
  (response) => {
    // Si la respuesta es correcta, simplemente devolvemos los datos
    // Esto nos ahorra poner .data en cada componente
    return response.data;
  },
  (error) => {
    // Si la respuesta es un error...
    if (error.response) {
      // 1. Token caducado o inválido
      if (error.response.status === 401) {
        localStorage.removeItem('token');
        window.location.href = '/login'; // Redirección forzosa
      }
      
      // 2. Error de servidor
      if (error.response.status === 500) {
        console.error("¡El servidor se ha caído!");
      }
    }
    
    return Promise.reject(error);
  }
);
Copied!

Refactorizando nuestro Componente

Veamos cómo queda nuestro componente ListaUsuarios del artículo anterior tras aplicar esta arquitectura.

import { useState, useEffect } from "react";
import api from "../api/axios"; // Importamos nuestra instancia

export default function ListaUsuarios() {
  const [users, setUsers] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        // 1. Sintaxis más limpia
        // 2. No hace falta poner la URL completa
        // 3. No hace falta .json() (el interceptor ya devolvió response.data)
        const data = await api.get("/users");
        
        setUsers(data);
      } catch (err) {
        // Axios nos da el mensaje de error detallado
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  if (loading) return <p>Cargando...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
  );
}
Copied!

Conclusión

Utilizar una instancia de Axios con interceptores es una de esas decisiones que se agradecen cuando el proyecto crece. Centraliza la lógica de red, simplifica los componentes y hace que el mantenimiento sea más llevadero.


Con esto, ya sabemos pedir datos. Pero a veces, hacemos cálculos pesados con esos datos o renderizamos listas gigantescas que ralentizan la app. Es el momento de entrar en la fase final del curso: Optimización y Rendimiento.