Proxy Pattern para Cacheo de Respuestas de API
Como implementar un proxy de cacheo que intercepta llamadas a APIs y almacena respuestas para reducir latencia y evitar peticiones redundantes
Nota para desarrolladores hispanohablantes: Esta guía incluye ejemplos y convenciones de nomenclatura adaptadas a equipos que trabajan en español. Cuando existen diferencias significativas en terminología técnica entre el inglés y el español, se indican explícitamente para facilitar la comunicación en equipos multiculturales.
Proxy Pattern para Cacheo de Respuestas de API
El Proxy pattern intercepta el acceso a un objeto para agregar comportamiento sin cambiar la implementacion original. Cuando se aplica a clientes de API, se convierte en una potente capa de cacheo que almacena respuestas, reduce latencia y protege servicios de peticiones redundantes.
Cuando Usar Esto
- Las respuestas de API son costosas de computar pero se leen frecuentemente
- Quieres evitar limites de rate en APIs de terceros
- La frescura de la respuesta puede controlarse por TTL en lugar de requerimientos en tiempo real
Problema
Cada llamada a una API externa dispara una peticion de red, serializacion y deserializacion. Para datos frecuentemente accedidos pero que cambian lentamente — como tasas de cambio, catalogos de productos o permisos de usuario — esto es ineficiente y lento.
Solucion
Implementa un proxy que envuelve el cliente real de la API y almacena respuestas en cache con expiracion configurable.
// api/WeatherClient.ts
interface WeatherClient {
getForecast(city: string): Promise<Forecast>;
}
// api/OpenWeatherClient.ts
class OpenWeatherClient implements WeatherClient {
async getForecast(city: string): Promise<Forecast> {
const res = await fetch(`https://api.openweathermap.org/data/2.5/forecast?q=${city}`);
return res.json();
}
}
// proxy/CachedWeatherClient.ts
class CachedWeatherClient implements WeatherClient {
private cache = new Map<string, { data: Forecast; expiry: number }>();
constructor(
private client: WeatherClient,
private ttlMs: number = 300_000
) {}
async getForecast(city: string): Promise<Forecast> {
const key = city.toLowerCase();
const cached = this.cache.get(key);
if (cached && cached.expiry > Date.now()) {
return cached.data;
}
const data = await this.client.getForecast(city);
this.cache.set(key, { data, expiry: Date.now() + this.ttlMs });
return data;
}
invalidate(city: string): void {
this.cache.delete(city.toLowerCase());
}
}
Uso
const realClient = new OpenWeatherClient();
const cachedClient = new CachedWeatherClient(realClient, 600_000);
const forecast = await cachedClient.getForecast('London');
Variaciones
- Redis Proxy: Almacena cache en Redis para sistemas distribuidos
- Smart Proxy: Agrega metricas, logging y circuit breaker junto al cacheo
- Lazy Proxy: Diferencia la inicializacion de conexiones costosas hasta el primer uso
Mejores Practicas
- Configura TTL basado en volatilidad de datos, no un valor fijo para todo
- Implementa hooks de invalidacion de cache para consistencia write-through
- Usa decorador o composicion para apilar multiples proxies
Errores Comunes
- Cachear respuestas de POST/PUT sin entender efectos secundarios
- No manejar eviccion de cache cuando crece la presion de memoria
- Devolver datos obsoletos silenciosamente sin logging
FAQ
P: Como se diferencia de una simple funcion wrapper? R: El Proxy pattern implementa la misma interfaz que el objeto real, asi que los llamadores no saben ni les importa si estan usando el cache o el cliente original.
P: Puedo combinar esto con el Decorator pattern? R: Si. Un Decorator agrega comportamiento; un Proxy controla acceso. Se usan frecuentemente juntos en la practica.