Skip to main content

Introducción

Esta guía cubre las mejores prácticas de seguridad, optimización del rendimiento y directrices de integración para ayudarte a construir aplicaciones robustas con la API de Lovi.

🔒 Mejores Prácticas de Seguridad

Gestión de Claves API

✅ HAZ:
  • Almacena las claves API en variables de entorno o gestión de configuración segura
  • Usa diferentes claves API para diferentes entornos (desarrollo, staging, producción)
  • Rota las claves API regularmente (recomendado: cada 90 días)
  • Monitoriza el uso de las claves API y configura alertas para actividad inusual
  • Usa el principio de mínimo privilegio (claves separadas para diferentes funciones si está disponible)
❌ NO HAGAS:
  • Codificar claves API en el código fuente o confirmarlas en el control de versiones
  • Compartir claves API por email, chat u otros canales no seguros
  • Usar claves API de producción en entornos de desarrollo
  • Registrar claves API completas en los registros de la aplicación

Seguridad de Autenticación

// ✅ Bueno - Almacenar en variables de entorno
const ACCESS_KEY = process.env.LOVI_ACCESS_KEY;

// ❌ Malo - Codificado en el código fuente
const ACCESS_KEY = 'tu-clave-api-real-aqui';

Seguridad de Solicitudes

Siempre usa HTTPS:
// ✅ Bueno - Solo HTTPS
const BASE_URL = 'https://cloud.lovi.ai';

// ❌ Malo - HTTP no seguro
const BASE_URL = 'http://cloud.lovi.ai';
Valida los datos de entrada:
function validatePhoneNumber(number) {
  const cleaned = number.replace(/\D/g, '');
  if (!/^\d{10,15}$/.test(cleaned)) {
    throw new Error('Formato de número de teléfono inválido');
  }
  return cleaned;
}

⚡ Optimización del Rendimiento

Gestión de Conexiones

Reutiliza conexiones HTTP:
const https = require('https');
const agent = new https.Agent({
  keepAlive: true,
  maxSockets: 10
});

Procesamiento por Lotes

Procesa las notificaciones en lotes:
async function sendNotificationsBatch(notifications, batchSize = 10) {
  const results = [];
  for (let i = 0; i < notifications.length; i += batchSize) {
    const batch = notifications.slice(i, i + batchSize);
    const batchPromises = batch.map(notification =>
      sendNotification(notification)
    );
    const batchResults = await Promise.allSettled(batchPromises);
    results.push(...batchResults);
    if (i + batchSize < notifications.length) {
      await sleep(100);
    }
  }
  return results;
}

Estrategias de Caché

Almacena en caché la información de plantillas:
class TemplateCache {
  constructor(ttl = 3600000) {
    this.cache = new Map();
    this.ttl = ttl;
  }
  async getTemplate(templateName) {
    const cached = this.cache.get(templateName);
    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.data;
    }
    const template = await fetchTemplateFromAPI(templateName);
    this.cache.set(templateName, { data: template, timestamp: Date.now() });
    return template;
  }
}

📊 Límites de Tasa y Throttling

Límites de Tasa

OperaciónLímiteVentana
Autenticación10 solicitudes1 minuto
Notificaciones100 solicitudes1 minuto
Recuperación de plantillas50 solicitudes1 minuto
Creación de plantillas5 solicitudes1 hora

🧪 Estrategias de Pruebas

Pruebas Unitarias

const mockAPIClient = {
  post: jest.fn()
};

describe('NotificationService', () => {
  test('debe enviar notificación de WhatsApp correctamente', async () => {
    mockAPIClient.post.mockResolvedValue({
      success: true,
      notification_id: 'test-123'
    });

    const service = new NotificationService(mockAPIClient);
    const result = await service.sendWhatsApp({
      phoneNumber: '34666033135',
      templateName: 'welcome',
      contactName: 'Juan García'
    });

    expect(result.success).toBe(true);
    expect(mockAPIClient.post).toHaveBeenCalledWith('/notify', expect.any(Object));
  });
});

🔍 Monitorización y Registro

Registro Estructurado

const logger = require('winston');

async function loggedAPICall(endpoint, data) {
  const requestId = generateRequestId();
  logger.info('Solicitud API iniciada', {
    request_id: requestId,
    endpoint: endpoint,
    method: 'POST',
    timestamp: new Date().toISOString()
  });

  try {
    const response = await makeAPICall(endpoint, data);
    logger.info('Solicitud API completada', {
      request_id: requestId,
      status_code: response.status,
      success: true
    });
    return response;
  } catch (error) {
    logger.error('Solicitud API fallida', {
      request_id: requestId,
      error: error.message,
      status_code: error.statusCode
    });
    throw error;
  }
}

🚨 Errores Comunes y Soluciones

Error: Valores Codificados

// ❌ Malo
const templateName = 'welcome_template_final_v2';

// ✅ Bueno
const templateName = config.templates.welcome;

Error: Manejo Deficiente de Errores

// ❌ Malo
try {
  await sendNotification(data);
} catch (error) {
  console.log('Error:', error);
}

// ✅ Bueno
try {
  await sendNotification(data);
} catch (error) {
  logger.error('Notificación fallida', {
    error: error.message,
    data: sanitizeForLog(data),
    stack: error.stack
  });
  throw new NotificationError(
    'Error al enviar la notificación',
    error.statusCode,
    error.requestId
  );
}

Error: Ignorar los Límites de Tasa

// ❌ Malo - Enviar todo a la vez
notifications.forEach(notification => {
  sendNotification(notification);
});

// ✅ Bueno - Respetar los límites de tasa
await sendNotificationsBatch(notifications, 10);
Recuerda: Seguir estas mejores prácticas te ayudará a construir integraciones más confiables, seguras y mantenibles con la API de Lovi.