DEV Community

Ashifur nahid
Ashifur nahid

Posted on

Spring Cloud Gateway Explained Simply: Routing, Filters, and Real-Life Use Cases

What Is an API Gateway?

In modern software development, applications are no longer built as one large, monolithic system. Instead, teams break systems into microservices—small, independent services responsible for specific tasks. While microservices improve scalability and maintainability, they also introduce a big challenge:

How do clients interact with many services without getting lost in complexity?

This is where an API Gateway comes in.

Definition: An API Gateway is a server that acts as the single entry point for all client requests in a microservices architecture.

Instead of calling each service individually, clients send every request to the Gateway, and the gateway routes the request to the appropriate backend service.

Introduction of Spring Cloud Gateway

Spring Cloud Gateway is a non-blocking, reactive API gateway built on Spring WebFlux. It provides a simple yet effective way to route to APIs and cross-cutting concerns like security, monitoring, and resilience.

What is it?
Spring Cloud Gateway acts as a reverse proxy that sits between clients and your microservices. It routes requests to appropriate backend services while applying cross-cutting concerns.

Why use it?

  • Centralizes common functionality (auth, logging, rate limiting)
  • Reduces code duplication across microservices
  • Provides a single entry point for your system
  • Handles service discovery and load balancing
  • Better performance with non-blocking architecture

When to use it?

  • Building microservice architectures
  • Need centralized authentication/authorization
  • Want to hide internal service structure from clients
  • Need to aggregate multiple service calls
  • Require API versioning and routing strategies

Use Cases of this Gateway

  • API Gateway Pattern: Single entry point for microservices
  • Load Balancing: Distribute traffic across service instances
  • Security Gateway: Centralized authentication and authorization
  • Request Transformation: Modify headers, body, or paths
  • Rate Limiting: Protect backend services from overload
  • Circuit Breaking: Handle service failures gracefully

Application Types Best Suited For:

  • E-commerce platforms: Handle high traffic, multiple services (cart, payment, inventory)
  • SaaS applications: Multi-tenant support, API versioning
  • Mobile backends: Single API endpoint for mobile apps
  • Microservice ecosystems: Service mesh entry point
  • Public APIs: Rate limiting, authentication, documentation

Core Concepts

Understanding the Building Blocks

Spring Cloud Gateway operates on three fundamental concepts that work together to route and process requests.

Route:

What is it?
A route is the fundamental building block that defines how a request should be handled. Think of it as a rule that says “if a request matches these conditions, send it to this destination with these modifications.”

A route consists of:

  • ID: Unique identifier for the route (used for monitoring and debugging)
  • Destination URI: Where to forward the request (can be a direct URL or load-balanced service name) - Predicates: Conditions that must be met for this route to match (like a filter in your email)
  • Filters: Modifications to apply before/after routing (like middleware)

Why use it?
Routes give you fine-grained control over how requests flow through your system. You can have different routes for different API versions, tenants, or authorization levels.

When to use it?

  • Routing requests to different microservices based on path
  • Implementing API versioning
  • A/B testing with weighted routing
  • Canary deployments

Application examples:

  • E-commerce: Route /products to catalog service, /orders to order service
  • SaaS: Route based on tenant subdomain (tenant1.example.com vs tenant2.example.com)
  • Mobile apps: Route based on app version header

Predicate

What is it?
Predicates are conditions that determine if a route matches a request. They work like “if” statements - the route only activates if all predicates are true.

Why use it?
Predicates enable intelligent routing based on request characteristics. They’re the decision-makers that determine which route handles which request.

When to use it?

  • Route based on URL path patterns
  • Route based on HTTP methods (GET vs POST)
  • Route based on headers (API version, authentication tokens)
  • Route based on query parameters
  • Time-based routing (maintenance windows, feature flags)

Application examples:

  • Mobile apps: Route based on “X-App-Version” header
  • Multi-region: Route based on “X-Region” header
  • Beta features: Route based on query parameter ?beta=true

Filter

What is it?
Filters modify incoming requests or outgoing responses. They work like middleware that can inspect, modify, or enrich data as it flows through the gateway.

Why use it?
Filters centralize cross-cutting concerns so you don’t repeat code in every microservice. They also protect backend services by handling concerns at the edge.

When to use it?

  • Add authentication headers
  • Log requests and responses
  • Transform request/response bodies
  • Add rate limiting
  • Implement circuit breakers
  • Modify paths before forwarding

Application examples:

  • Add correlation IDs for distributed tracing
  • Strip sensitive headers before forwarding
  • Transform legacy API responses to new format
  • Add caching headers to responses

Getting Started

Add this library to you gateway application:

<dependencies>
    <!-- Spring Cloud Gateway -->   
     <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!-- Service Discovery (Optional) -->  
     <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2023.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
Enter fullscreen mode Exit fullscreen mode

Add this in application.yml

server:
  port: 8080

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
Enter fullscreen mode Exit fullscreen mode

Route Configuration

YAML Configuration (Declarative)

What is it?
Declarative configuration using YAML files allows you to define routes without writing Java code. This is the most common and recommended approach for static routes.

Why use it?

  • Easy to read and maintain
  • No compilation needed - just restart the application
  • Perfect for configuration management systems (Git, Config Server)
  • Ideal for DevOps teams who may not be Java experts
  • Can be externalized and changed without code deployment

When to use it?

  • Static routes that don’t change frequently
  • Configuration-driven routing
  • When you need to externalize routing logic
  • Team prefers infrastructure-as-code approach

Application examples:

  • Standard microservice routing (user service, order service, payment service)
  • API versioning with clear separation
  • Multi-environment configurations (dev, staging, production)
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://USER-SERVICE
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=1
            - AddRequestHeader=X-Request-Source, Gateway

        - id: order-service
          uri: lb://ORDER-SERVICE
          predicates:
            - Path=/api/orders/**
            - Method=GET,POST
          filters:
            - StripPrefix=1
            - RewritePath=/api/orders/(?<segment>.*), /$\{segment}

        - id: payment-service
          uri: https://payment-api.example.com
          predicates:
            - Path=/api/payments/**
            - Header=X-API-Version, v1
          filters:
            - CircuitBreaker=paymentCircuitBreaker
Enter fullscreen mode Exit fullscreen mode

Java Configuration (Programmatic)

What is it?
Programmatic route configuration using Java code gives you full control and type safety. Routes are defined as beans in Spring configuration classes.

Why use it?

  • Full power of Java (loops, conditions, external data sources)
  • Type-safe configuration with IDE support
  • Can load routes from databases or external APIs
  • Better for complex routing logic
  • Easier to test with unit tests

When to use it?

  • Dynamic routes based on database or external configuration
  • Complex routing logic with conditions
  • Need to inject dependencies into route configuration
  • Routes need to be created at runtime
  • When type safety is critical

Application examples:

  • Multi-tenant systems where routes are stored in database per tenant
  • Dynamic API gateway where customers can configure their own routes
  • A/B testing with dynamic traffic splitting
  • Feature flags that enable/disable routes
@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service", r -> r
                .path("/api/users/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .addRequestHeader("X-Request-Source", "Gateway")
                    .retry(config -> config
                        .setRetries(3)
                        .setStatuses(HttpStatus.INTERNAL_SERVER_ERROR)
                    )
                )
                .uri("lb://USER-SERVICE")
            )
            .route("order-service", r -> r
                .path("/api/orders/**")
                .and()
                .method(HttpMethod.GET, HttpMethod.POST)
                .filters(f -> f
                    .stripPrefix(1)
                    .rewritePath("/api/orders/(?<segment>.*)", "/${segment}")
                )
                .uri("lb://ORDER-SERVICE")
            )
            .build();
    }
}
Enter fullscreen mode Exit fullscreen mode

Predicates

What are Predicates?
Predicates are the “if conditions” of your gateway. They determine which route handles which request by matching against various request attributes. Think of them as sophisticated URL pattern matching with superpowers.

Why use Predicates?

  • Enable intelligent request routing without coding
  • Support complex matching scenarios
  • Combine multiple conditions (AND logic)
  • Make routing decisions based on runtime data

When to use Predicates?

  • Different services handle different URL paths
  • Route based on HTTP method (GET, POST, DELETE)
  • API versioning via headers
  • A/B testing based on query parameters
  • Regional routing based on host/headers
  • Time-based routing (maintenance windows, scheduled deployments)

Application examples:

  • E-commerce: Route /products to catalog service, /checkout to payment service
  • SaaS: Route based on tenant ID in header or subdomain
  • Mobile API: Route based on app version to maintain backward compatibility
  • Financial systems: Route based on transaction amount (small to service A, large to service B for additional verification)

Predicates match HTTP requests based on various criteria.

Common Predicates

spring:
  cloud:
    gateway:
      routes:
        # Path-based routing
        - id: path-route
          uri: lb://SERVICE-A
          predicates:
            - Path=/api/v1/**

        # Method-based routing
        - id: method-route
          uri: lb://SERVICE-B
          predicates:
            - Method=GET,POST

        # Header-based routing
        - id: header-route
          uri: lb://SERVICE-C
          predicates:
            - Header=X-API-Version, v2

        # Query parameter routing
        - id: query-route
          uri: lb://SERVICE-D
          predicates:
            - Query=type, premium

        # Host-based routing
        - id: host-route
          uri: lb://SERVICE-E
          predicates:
            - Host=api.example.com

        # Time-based routing (e.g., maintenance window)
        - id: time-route
          uri: lb://SERVICE-F
          predicates:
            - Before=2025-12-31T23:59:59+06:00[Asia/Dhaka]
Enter fullscreen mode Exit fullscreen mode

Top comments (0)