@authuser/http-react
v1.0.2
Published
Authuser HTTP React package for integrating with React Query.
Maintainers
Readme
@authuser/http-react
Adaptador de React para @authuser/http-core, basado en @tanstack/react-query.
Incluye hooks declarativos (useHttpQuery, useHttpMutation) con soporte para:
- Caché (memoria o persistente)
- Reintentos automáticos
- Rate limiting
- Duplicados de peticiones simultáneas
- Middleware extensible
- Tipado completo en TypeScript
📦 Instalación
npm install @authuser/http-reactNota: Este paquete incluye todas las dependencias necesarias (@authuser/http-core, @tanstack/react-query, axios). No necesitas instalar nada más.
🚀 Uso básico
1. Crea el HttpService
// src/lib/http.ts
import { HttpService, AxiosHttpClient, LocalSessionManager } from '@authuser/http-core';
import { LocalStorageCache, LocalStoragePersistence } from '@authuser/http-react';
// Prefijos opcionales para organizar localStorage
const APP_PREFIX = 'myapp'; // ← Tu identificador de app
export const http = new HttpService({
client: new AxiosHttpClient(),
session: new LocalSessionManager(),
cache: new LocalStorageCache(`${APP_PREFIX}-cache`), // caché temporal con TTL
persistence: new LocalStoragePersistence(`${APP_PREFIX}-persist`), // persistencia permanente
config: {
baseUrl: import.meta.env.VITE_API_URL,
cache: { enabled: true, ttlMs: 60_000 },
retry: {
enabled: true,
maxAttempts: 1,
delay: 500,
backoff: 'exponential',
skipOnEndpoint: ['/auth/login'],
skipOnStatusCode: [401, 429],
},
},
});2. Envuelve tu app
// src/main.tsx
import { HttpProvider } from '@authuser/http-react';
import { http } from './lib/http';
import App from './App';
function Root() {
return (
<HttpProvider service={http}>
<App />
</HttpProvider>
);
}💡 Nota:
HttpProviderya incluye internamenteQueryClientProvider, por lo que solo necesitas un provider.
Configuración avanzada (opcional)
Si necesitas personalizar el QueryClient:
import { HttpProvider } from '@authuser/http-react';
import { QueryClient } from '@tanstack/react-query';
import { http } from './lib/http';
import App from './App';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 60_000, // 1 minuto
cacheTime: 300_000, // 5 minutos
},
},
});
function Root() {
return (
<HttpProvider service={http} queryClient={queryClient}>
<App />
</HttpProvider>
);
}🧪 Hooks disponibles
🔍 useHttpQuery
| Característica | Valor |
| ------------------ | ------------------------------------ |
| Basado en | useQuery |
| Caché automática | ✅ Sí (memoiza resultados por clave) |
| Reintentos | ✅ Sí (según config retry) |
| Refetch automático | ✅ Sí (focus / reconexión) |
| Uso típico | GET / datos |
import { useHttpQuery } from '@authuser/http-react';
// Ejemplo básico con caché temporal
const { data, isLoading, error } = useHttpQuery<User[]>({ url: '/users', cache: true });
// Con persistencia offline-first
const { data, isLoading, error } = useHttpQuery<User[]>({
url: '/user/profile',
persist: true,
persistKey: 'user-profile',
});
// Con opciones de React Query
const { data, isLoading, error } = useHttpQuery<User[]>(
{ url: '/users', query: { role: 'admin' } },
{ staleTime: 1000 * 30, refetchOnWindowFocus: false }
);Parámetros:
req: ObjetoHttpRequestsinmethod(o conmethod: 'GET'opcional)options: Opciones deuseQueryde React Query (opcional)
✏️ useHttpMutation
| Característica | Valor |
| -------------- | --------------------------- |
| Basado en | useMutation |
| Caché | ❌ No |
| Refetch | ❌ No automático |
| Uso típico | POST / PUT / PATCH / DELETE |
import { useHttpMutation } from '@authuser/http-react';
// Ejemplo básico
const { mutate, isPending, isSuccess } = useHttpMutation<User, { name: string }>();
mutate({
url: '/users',
method: 'POST',
body: { name: 'Neo' },
});
// Con callbacks
const { mutate } = useHttpMutation<User, NewUserData>({
onSuccess: (data) => {
console.log('Usuario creado:', data);
},
onError: (error) => {
console.error('Error:', error);
},
});Parámetros:
options: Opciones deuseMutationde React Query (opcional)
Genéricos:
TRes: Tipo de la respuestaTBody: Tipo del body de la petición
🔑 Prefijos y Organización
Tanto LocalStorageCache como LocalStoragePersistence aceptan un prefijo opcional para organizar las claves en localStorage:
// ✅ Opción 1: Sin prefijo (usa valores por defecto)
const cache = new LocalStorageCache(); // '__http_cache__'
const persistence = new LocalStoragePersistence(); // 'http-persist:'
// ✅ Opción 2: Con prefijo de tu app (recomendado)
const APP_PREFIX = 'myapp';
const cache = new LocalStorageCache(`${APP_PREFIX}-cache`);
const persistence = new LocalStoragePersistence(`${APP_PREFIX}-persist`);
// ✅ Opción 3: Con dominio inverso (estilo Java/Android)
const cache = new LocalStorageCache('com.mycompany.myapp.cache');
const persistence = new LocalStoragePersistence('com.mycompany.myapp.persist');¿Por qué usar prefijos?
- Evita colisiones: Si tienes múltiples apps en el mismo dominio
- Identificación clara: Fácil de identificar en DevTools
- Limpieza selectiva: Puedes borrar solo datos de tu app
Ejemplo de claves generadas
const cache = new LocalStorageCache('myapp-cache');
const persistence = new LocalStoragePersistence('myapp-persist');
// Generará claves como:
// 'myapp-cache:GET|/user/profile||'
// 'myapp-persist:user-profile'🔧 Persistencia Offline-First
El paquete incluye soporte para persistencia permanente de respuestas, ideal para funcionalidad offline:
LocalStoragePersistence
Almacena respuestas HTTP de forma permanente en localStorage para acceso offline:
import { LocalStoragePersistence } from '@authuser/http-react';
// En tu configuración de HttpService
const persistence = new LocalStoragePersistence('myapp-persist');
const http = new HttpService({
client: new AxiosHttpClient(),
persistence,
config: { baseUrl: '/api', retry: { enabled: true } },
});Ejemplo de uso en componentes
import { useHttpQuery } from '@authuser/http-react';
import { useState, useEffect } from 'react';
function UserProfile() {
const [isOffline, setIsOffline] = useState(false);
// Petición con persistencia - funcionará offline
const {
data: profile,
isLoading,
error,
} = useHttpQuery<UserProfile>({
url: '/user/profile',
persist: true,
persistKey: 'user-profile',
requiresAuth: true,
});
useEffect(() => {
// Detectar cuando estamos offline y mostrando datos persistidos
if (error && !navigator.onLine) {
setIsOffline(true);
} else {
setIsOffline(false);
}
}, [error]);
if (isLoading) return <Spinner />;
return (
<div>
{isOffline && (
<Banner type="warning">📴 Modo Offline - Mostrando datos guardados</Banner>
)}
{profile && <ProfileCard name={profile.name} email={profile.email} />}
</div>
);
}Casos de uso comunes
// 1. Configuración de la app (siempre disponible)
const { data: config } = useHttpQuery({
url: '/config/app',
persist: true,
persistKey: 'app-config',
});
// 2. Datos del usuario
const { data: user } = useHttpQuery({
url: '/user/me',
persist: true,
persistKey: 'current-user',
requiresAuth: true,
});
// 3. Contenido offline (artículos, productos, etc.)
const { data: articles } = useHttpQuery({
url: '/articles/latest',
persist: true,
persistKey: 'latest-articles',
});
// 4. Dashboard con métricas
const { data: metrics } = useHttpQuery({
url: '/dashboard/metrics',
persist: true,
persistKey: 'dashboard-metrics',
cache: true, // También usar caché para performance
});⚠️ Diferencia entre Cache y Persistencia
| | Cache | Persistencia | | -------------------- | -------------- | --------------------- | | Duración | Temporal (TTL) | Permanente | | Propósito | Performance | Soporte offline | | Expira | ✅ Sí | ❌ No | | Fallback offline | ❌ No | ✅ Sí | | Actualización | Después de TTL | Cada petición exitosa |
Recomendación: Usa cache: true + persist: true para máximo performance Y soporte offline.
�🎯 Exportaciones del paquete
export { useHttpQuery } from './hooks/useHttpQuery';
export { useHttpMutation } from './hooks/useHttpMutation';
export { HttpProvider, useHttpService } from './provider/HttpContext';
export { LocalStorageCache } from './infrastructure/LocalStorageCache';
export { LocalStoragePersistence } from './infrastructure/LocalStoragePersistence';🔁 RetryConfig
type RetryConfig = {
enabled?: boolean;
maxAttempts?: number;
delay?: number;
backoff?: 'linear' | 'exponential' | 'fixed';
skipOnStatusCode?: number[];
skipOnEndpoint?: string[];
onRetry?: (retryCount: number, error: AxiosError, config: any) => void;
};🧱 Tipos avanzados
type User = { id: string; name: string };
type NewUser = { name: string };
const { data } = useHttpQuery<User[]>({ url: '/users' });
const { mutate } = useHttpMutation<User, NewUser>();🧠 Resumen práctico
| Caso | Hook recomendado |
| ----------------------------- | ----------------- |
| Obtener lista de productos | useHttpQuery |
| Obtener detalle de un vídeo | useHttpQuery |
| Crear nuevo usuario | useHttpMutation |
| Enviar formulario de contacto | useHttpMutation |
| Actualizar perfil de usuario | useHttpMutation |
| Borrar comentario | useHttpMutation |
🧩 Personalización
SessionManager personalizado
import { SessionManagerPort } from '@authuser/http-core';
class MyCustomSessionManager implements SessionManagerPort {
async getToken(): Promise<string | null> {
return localStorage.getItem('my_token');
}
async refreshToken(): Promise<string | null> {
const response = await fetch('/api/refresh', { method: 'POST' });
const { token } = await response.json();
localStorage.setItem('my_token', token);
return token;
}
async logout(): Promise<void> {
localStorage.removeItem('my_token');
}
}
export const http = new HttpService({
client: new AxiosHttpClient(),
session: new MyCustomSessionManager(),
config: { baseUrl: '/api', retry: { enabled: true, maxAttempts: 2 } },
});LocalStorageCache
El paquete incluye LocalStorageCache que implementa CachePort para persistir la caché HTTP en localStorage:
import { LocalStorageCache } from '@authuser/http-react';
const cache = new LocalStorageCache();
// Usa el prefijo '__http_cache__' internamente
// Gestiona automáticamente la expiración basada en TTL📁 Estructura recomendada
src/
├─ lib/
│ ├─ http.ts ← instancia de HttpService
│ └─ session.ts ← implementación de SessionManager
├─ pages/
│ └─ Users.tsx ← useHttpQuery
├─ App.tsx
└─ main.tsx ← montaje de providers🧪 Testing
Puedes mockear HttpService o usar msw para interceptar peticiones.
Para unit tests, usa createTestQueryClient() de TanStack Query.
🛠️ Dependencias
Dependencies (incluidas automáticamente)
@authuser/http-core: ^1.6.0 (incluyeaxios)@tanstack/react-query: ^5.0.0- Babel presets para desarrollo
Peer Dependencies (debes tenerlas en tu proyecto)
react: >=18.0.0
✨ Instalación simple: Un solo comando instala todo lo necesario.
📚 Más información
Para más detalles sobre configuración, middlewares y opciones avanzadas, consulta la documentación de @authuser/http-core.
