Probar gratis
8 min lectura Guide 855 of 877

Patrones y Estrategias de Implementación de API Gateway

Los API gateways sirven como el único punto de entrada para que las aplicaciones cliente accedan a microservicios, proporcionando preocupaciones transversales esenciales como autenticación, limitación de tasa, enrutamiento y monitoreo. Comprender los patrones de gateway es crucial para construir sistemas distribuidos escalables y seguros.

Arquitectura Central de API Gateway

Ubicación de Gateway en Microservicios

API Gateway como Único Punto de Entrada:

Internet ──► API Gateway ──► Service Registry
    │              │               │
    ▼              ▼               ▼
Clients ──────────┼───────────────┼─► Microservicio A
                  │               │
                  └───────────────┼─► Microservicio B
                                  │
                                  └─► Microservicio C

Responsabilidades del Gateway:

  • Enrutamiento de Solicitudes: Dirigir solicitudes a servicios apropiados
  • Autenticación: Validar credenciales y permisos de usuario
  • Limitación de Tasa: Controlar tasas de solicitud para prevenir abuso
  • Balanceo de Carga: Distribuir solicitudes entre instancias de servicio
  • Monitoreo: Rastrear métricas de solicitud y salud

Patrones de Enrutamiento

Enrutamiento Basado en Ruta

Mapeo de Ruta URL:

/api/v1/users/* ──► User Service
/api/v1/orders/* ──► Order Service
/api/v1/products/* ──► Product Service

Ejemplo de Implementación:

location /api/v1/users/ {
    proxy_pass http://user-service:8080/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

location /api/v1/orders/ {
    proxy_pass http://order-service:8080/;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

Enrutamiento Basado en Encabezado

Enrutamiento por Content-Type:

Content-Type: application/json ──► JSON Service
Content-Type: application/xml ──► XML Service

Enrutamiento Basado en Versión:

X-API-Version: v1 ──► Legacy Service
X-API-Version: v2 ──► Modern Service

Enrutamiento Dinámico con Descubrimiento de Servicio

Integración con Service Registry:

API Gateway ──► Consul/Eureka ──► Service Instances
     │                                      │
     └─► Health Check ──► Load Balance ──► Route Request

Autenticación y Autorización

Validación de Token JWT

Flujo JWT:

Client ──► JWT Token ──► Gateway ──► Validate Token ──► Service
     ▲                      │               │
     └──────────────────────┴───────────────┘
                Token Refresh

Implementación de Validación de Token:

class JwtAuthMiddleware {
  async validateToken(token: string): Promise<UserClaims> {
    try {
      const decoded = jwt.verify(token, process.env.JWT_SECRET);
      return {
        userId: decoded.sub,
        roles: decoded.roles,
        permissions: decoded.permissions
      };
    } catch (error) {
      throw new AuthenticationError('Invalid token');
    }
  }

  async authorizeRequest(claims: UserClaims, requiredRoles: string[]): Promise<boolean> {
    return requiredRoles.some(role => claims.roles.includes(role));
  }
}

Integración OAuth2

Flujo de Código de Autorización:

Client ──► Gateway ──► Auth Server ──► User Consent ──► Tokens
     ▲              │                    │                    │
     └──────────────┼────────────────────┼────────────────────┘
          Redirect with Code ──► Exchange for Tokens

Autenticación por Clave API

Acceso Basado en Clave:

class ApiKeyMiddleware {
  private keyStore: Map<string, ApiKeyConfig> = new Map();

  async validateApiKey(apiKey: string): Promise<boolean> {
    const config = this.keyStore.get(apiKey);
    if (!config) return false;

    // Check rate limits, expiration, etc.
    return config.active && !this.isExpired(config);
  }

  async getRateLimit(apiKey: string): Promise<RateLimit> {
    const config = this.keyStore.get(apiKey);
    return config?.rateLimit || { requests: 100, period: '1h' };
  }
}

Patrones de Limitación de Tasa

Algoritmo Token Bucket

Implementación Token Bucket:

class TokenBucket {
  private tokens: number;
  private lastRefill: number;
  private readonly capacity: number;
  private readonly refillRate: number; // tokens per second

  constructor(capacity: number, refillRate: number) {
    this.capacity = capacity;
    this.refillRate = refillRate;
    this.tokens = capacity;
    this.lastRefill = Date.now();
  }

  allowRequest(): boolean {
    this.refill();
    if (this.tokens >= 1) {
      this.tokens--;
      return true;
    }
    return false;
  }

  private refill(): void {
    const now = Date.now();
    const timePassed = (now - this.lastRefill) / 1000;
    const tokensToAdd = timePassed * this.refillRate;

    this.tokens = Math.min(this.capacity, this.tokens + tokensToAdd);
    this.lastRefill = now;
  }
}

Contador de Ventana Deslizante

Limitación de Tasa Distribuida:

class SlidingWindowLimiter {
  private redis: Redis;

  async isAllowed(key: string, limit: number, windowMs: number): Promise<boolean> {
    const now = Date.now();
    const windowStart = now - windowMs;

    // Remove old entries
    await this.redis.zremrangebyscore(key, 0, windowStart);

    // Count current requests
    const requestCount = await this.redis.zcard(key);

    if (requestCount >= limit) {
      return false;
    }

    // Add current request
    await this.redis.zadd(key, now, `${now}-${Math.random()}`);
    await this.redis.expire(key, Math.ceil(windowMs / 1000));

    return true;
  }
}

Transformación de Solicitudes

Transformación de Datos

Enriquecimiento de Solicitud:

Incoming Request ──► Add User Context ──► Service
     │                        │
     └─► {userId: 123} ───────┘

Transformación de Respuesta:

Service Response ──► Remove Sensitive Data ──► Client
     │                           │
     └─► Filter Fields ──────────┘

Traducción de Protocolo

REST a GraphQL:

REST API ──► Gateway ──► GraphQL Schema ──► Resolvers
     │              │          │
     └──────────────┼──────────┘
          Query Optimization

Estrategias de Cache

Cache de Respuesta

Encabezados de Cache HTTP:

class CacheMiddleware {
  async handleRequest(req: Request, res: Response): Promise<void> {
    const cacheKey = this.generateCacheKey(req);

    // Check cache
    const cached = await this.cache.get(cacheKey);
    if (cached && this.isCacheValid(cached, req)) {
      res.setHeader('X-Cache', 'HIT');
      res.send(cached.data);
      return;
    }

    // Set cache headers for response
    res.setHeader('Cache-Control', 'public, max-age=300');
    res.setHeader('ETag', this.generateETag(res.body));

    // Cache the response
    await this.cache.set(cacheKey, {
      data: res.body,
      headers: res.headers,
      timestamp: Date.now()
    });
  }
}

Cache Distribuido

Replicación de Cache:

API Gateway ──► Redis Cluster ──► Cache Hit
     │              │
     └──────────────┘
     Cache Miss → Origin

Patrón Circuit Breaker

Estados del Circuit Breaker

Máquina de Estados:

Closed ──► Open (when failures > threshold)
   ▲         │
   └─────────┼─► Half-Open (test request)
             │
             └─► Closed (if success)

Implementación:

enum CircuitState {
  CLOSED = 'CLOSED',
  OPEN = 'OPEN',
  HALF_OPEN = 'HALF_OPEN'
}

class CircuitBreaker {
  private state: CircuitState = CircuitState.CLOSED;
  private failureCount = 0;
  private lastFailureTime = 0;

  async execute<T>(operation: () => Promise<T>): Promise<T> {
    if (this.state === CircuitState.OPEN) {
      if (this.shouldAttemptReset()) {
        this.state = CircuitState.HALF_OPEN;
      } else {
        throw new CircuitBreakerError('Circuit is open');
      }
    }

    try {
      const result = await operation();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  private onSuccess(): void {
    this.failureCount = 0;
    this.state = CircuitState.CLOSED;
  }

  private onFailure(): void {
    this.failureCount++;
    this.lastFailureTime = Date.now();

    if (this.failureCount >= this.failureThreshold) {
      this.state = CircuitState.OPEN;
    }
  }
}

Monitoreo y Observabilidad

Métricas de Gateway

Métricas Principales a Rastrear:

  • Latencia de solicitud por endpoint
  • Tasas de error por servicio
  • Aciertos de limitación de tasa
  • Fallos de autenticación
  • Tasas de acierto/fallo de cache

Colección de Métricas:

class MetricsCollector {
  private metrics: Map<string, Metric> = new Map();

  recordRequest(endpoint: string, method: string, statusCode: number, duration: number): void {
    const key = `${method}:${endpoint}`;

    this.metrics.set(key, {
      count: (this.metrics.get(key)?.count || 0) + 1,
      totalDuration: (this.metrics.get(key)?.totalDuration || 0) + duration,
      statusCodes: {
        ...this.metrics.get(key)?.statusCodes,
        [statusCode]: (this.metrics.get(key)?.statusCodes?.[statusCode] || 0) + 1
      }
    });
  }

  getMetrics(): GatewayMetrics {
    return {
      endpoints: Array.from(this.metrics.entries()).map(([key, metric]) => ({
        endpoint: key,
        requests: metric.count,
        avgLatency: metric.totalDuration / metric.count,
        statusCodes: metric.statusCodes
      }))
    };
  }
}

Rastreo Distribuido

Rastreo de Solicitud:

Client Request ──► Gateway (span-1) ──► Service A (span-2) ──► Service B (span-3)
     │                      │                      │                      │
     └─ Trace ID: abc-123 ──┼─ Parent: span-1 ─────┼─ Parent: span-2 ─────┘

Orquestación de Servicio

Composición de API

Agregación de Solicitudes:

Gateway ──► Parallel Requests ──► Combine Results
    │         ├─► Service A
    │         ├─► Service B
    │         └─► Service C
    │
    └─► Single Response

Orquestación Saga

Coordinación de Transacción Distribuida:

Gateway ──► Start Saga ──► Service A ──► Service B ──► Complete
     │         │              │              │
     └─────────┼──────────────┼──────────────┘
       Compensate on Failure

Mejores Prácticas de Seguridad

Validación y Sanitización de Entrada

Validación de Solicitud:

class ValidationMiddleware {
  async validateRequest(req: Request): Promise<ValidationResult> {
    const schema = this.getSchema(req.path);

    try {
      const validated = await schema.validate(req.body);
      return { valid: true, data: validated };
    } catch (error) {
      return {
        valid: false,
        errors: error.errors.map(err => ({
          field: err.field,
          message: err.message
        }))
      };
    }
  }
}

Configuración CORS

Cross-Origin Resource Sharing:

const corsOptions = {
  origin: (origin, callback) => {
    const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || [];
    if (allowedOrigins.includes(origin) || !origin) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-API-Key']
};

Optimización de Rendimiento

Pooling de Conexiones

Configuración de Cliente HTTP:

const httpClient = axios.create({
  baseURL: 'http://service-registry',
  timeout: 5000,
  httpAgent: new http.Agent({
    keepAlive: true,
    maxSockets: 100,
    maxFreeSockets: 10,
    timeout: 60000
  })
});

Compresión de Respuesta

Compresión Gzip:

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1024;
gzip_comp_level 6;

Integración con GitScrum

Dashboard de Monitoreo de Gateway

Rastreo de Salud de API Gateway:

  • Monitorear throughput y latencia de solicitud
  • Rastrear disponibilidad de servicio y tasas de error
  • Configurar alertas para fallos de gateway

Mapeo de Dependencia de Servicio

Visualización de Dependencia:

API Gateway ──► User Service ──► Auth Service
     │              │               │
     └──────────────┼───────────────┘
          Service Mesh Integration

Soluciones Relacionadas