0%
API Gateway avec Spring Cloud Gateway

API Gateway

API Gateway avec Spring Cloud Gateway

10-15 min

API Gateway avec Spring Cloud Gateway

L’API Gateway est un composant essentiel dans l’architecture microservices. Il sert de point d’entrée unique pour tous les clients et gère des aspects importants comme le routage, la sécurité, et la limitation de débit.

1. Configuration de l’API Gateway

1.1 Création du Projet Gateway

curl https://start.spring.io/starter.tgz \
    -d dependencies=cloud-gateway,cloud-eureka-client \
    -d groupId=com.example \
    -d artifactId=api-gateway \
    -d name=api-gateway \
    -d description=API%20Gateway%20for%20Microservices \
    -d packageName=com.example.gateway \
    -d packaging=jar \
    -d javaVersion=17 \
    -d type=maven-project \
    | tar -xzvf -

1.2 Configuration de Base

# application.yml
server:
  port: 8080

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:
        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/api/products/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                key-resolver: "#{@ipKeyResolver}"

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

2. Routage et Filtres

2.1 Configuration des Routes

@Configuration
public class RouteConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("order-service", r -> r
                .path("/api/orders/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .addResponseHeader("X-Response-Time", String.valueOf(System.currentTimeMillis())))
                .uri("lb://order-service"))
            .route("payment-service", r -> r
                .path("/api/payments/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .addResponseHeader("X-Response-Time", String.valueOf(System.currentTimeMillis())))
                .uri("lb://payment-service"))
            .build();
    }
}

2.2 Filtres Personnalisés

@Component
public class LoggingFilter implements GlobalFilter, Ordered {
    private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        logger.info("Path requested: {}", request.getURI().getPath());
        
        return chain.filter(exchange)
            .then(Mono.fromRunnable(() -> {
                ServerHttpResponse response = exchange.getResponse();
                logger.info("Response status: {}", response.getStatusCode());
            }));
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

3. Sécurité

3.1 Configuration JWT

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://localhost:9000
          jwk-set-uri: http://localhost:9000/.well-known/jwks.json

3.2 Filtre d’Authentification

@Component
public class JwtAuthenticationFilter implements GlobalFilter {
    private final JwtDecoder jwtDecoder;

    public JwtAuthenticationFilter(JwtDecoder jwtDecoder) {
        this.jwtDecoder = jwtDecoder;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String token = extractToken(request);
        
        if (token != null) {
            try {
                Jwt jwt = jwtDecoder.decode(token);
                ServerHttpRequest modifiedRequest = request.mutate()
                    .header("X-User-Id", jwt.getSubject())
                    .build();
                return chain.filter(exchange.mutate().request(modifiedRequest).build());
            } catch (JwtException e) {
                return unauthorized(exchange);
            }
        }
        
        return chain.filter(exchange);
    }

    private String extractToken(ServerHttpRequest request) {
        String bearerToken = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }

    private Mono<Void> unauthorized(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        return response.setComplete();
    }
}

4. Limitation de Débit

4.1 Configuration Redis

spring:
  redis:
    host: localhost
    port: 6379

4.2 Configuration du Rate Limiter

@Configuration
public class RateLimiterConfig {
    @Bean
    KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest().getRemoteAddress().getHostName()
        );
    }
}

5. Monitoring et Métriques

5.1 Configuration Actuator

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: always

5.2 Métriques Personnalisées

@Component
public class GatewayMetrics {
    private final MeterRegistry registry;
    private final Counter requestCounter;
    private final Timer requestLatency;

    public GatewayMetrics(MeterRegistry registry) {
        this.registry = registry;
        this.requestCounter = Counter.builder("gateway.requests")
            .description("Total number of requests")
            .tag("type", "all")
            .register(registry);
        
        this.requestLatency = Timer.builder("gateway.latency")
            .description("Request latency")
            .register(registry);
    }

    public void recordRequest() {
        requestCounter.increment();
    }

    public void recordLatency(long milliseconds) {
        requestLatency.record(milliseconds, TimeUnit.MILLISECONDS);
    }
}

Conclusion

L’API Gateway avec Spring Cloud Gateway offre plusieurs avantages :

  • Routage intelligent vers les microservices
  • Sécurité centralisée avec JWT
  • Limitation de débit pour protéger les services
  • Monitoring et métriques
  • Filtres personnalisables pour la transformation des requêtes

Dans le prochain tutoriel, nous verrons comment implémenter le pattern Circuit Breaker avec Resilience4J pour gérer la résilience de nos microservices.

Commentaires

Les commentaires sont alimentés par GitHub Discussions

Connectez-vous avec GitHub pour participer à la discussion

Lien copié !