Essayer gratuitement
9 min lecture Guide 855 of 877

Patrons et Stratégies d'Implémentation d'API Gateway

Les API gateways servent de point d'entrée unique pour que les applications cliente accèdent aux microservices, fournissant des préoccupations transversales essentielles comme l'authentification, la limitation de débit, le routage et le monitoring. Comprendre les patrons de gateway est crucial pour construire des systèmes distribués évolutifs et sécurisés.

Architecture Centrale d'API Gateway

Placement de Gateway dans les Microservices

API Gateway comme Point d'Entrée Unique :

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

Responsabilités du Gateway :

  • Routage des Demandes : Diriger les demandes vers les services appropriés
  • Authentification : Valider les identifiants et permissions utilisateur
  • Limitation de Débit : Contrôler les taux de demande pour prévenir l'abus
  • Équilibrage de Charge : Distribuer les demandes entre les instances de service
  • Monitoring : Suivre les métriques de demande et santé

Patrons de Routage

Routage Basé sur le Chemin

Mappage de Chemin URL :

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

Exemple d'Implémentation :

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;
}

Routage Basé sur l'En-tête

Routage par Content-Type :

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

Routage Basé sur la Version :

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

Routage Dynamique avec Découverte de Service

Intégration avec Service Registry :

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

Authentification et Autorisation

Validation de Token JWT

Flux JWT :

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

Implémentation de Validation 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));
  }
}

Intégration OAuth2

Flux de Code d'Autorisation :

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

Authentification par Clé API

Accès Basé sur Clé :

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' };
  }
}

Patrons de Limitation de Débit

Algorithme Token Bucket

Implémentation 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;
  }
}

Compteur de Fenêtre Glissante

Limitation de Débit Distribuée :

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;
  }
}

Transformation de Demandes

Transformation de Données

Enrichissement de Demande :

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

Transformation de Réponse :

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

Traduction de Protocole

REST vers GraphQL :

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

Stratégies de Cache

Cache de Réponse

En-têtes 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 Distribué

Réplication de Cache :

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

Patron Circuit Breaker

États du Circuit Breaker

Machine d'États :

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

Implémentation :

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;
    }
  }
}

Monitoring et Observabilité

Métriques de Gateway

Métriques Principales à Suivre :

  • Latence de demande par endpoint
  • Taux d'erreur par service
  • Succès de limitation de débit
  • Échecs d'authentification
  • Taux de succès/échec de cache

Collecte de Métriques :

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
      }))
    };
  }
}

Traçage Distribué

Traçage de Demande :

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

Orchestration de Service

Composition d'API

Agrégation de Demandes :

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

Orchestration Saga

Coordination de Transaction Distribuée :

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

Meilleures Pratiques de Sécurité

Validation et Sanitisation d'Entrée

Validation de Demande :

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
        }))
      };
    }
  }
}

Configuration 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']
};

Optimisation des Performances

Pooling de Connexions

Configuration de Client HTTP :

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

Compression de Réponse

Compression 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;

Intégration avec GitScrum

Dashboard de Monitoring de Gateway

Suivi de Santé d'API Gateway :

  • Monitorer le débit et la latence de demande
  • Suivre la disponibilité de service et les taux d'erreur
  • Configurer des alertes pour les pannes de gateway

Mappage de Dépendance de Service

Visualisation de Dépendance :

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

Solutions Connexes