Spring Cloud Gateway Features

Reading Time: 4 minutes
spring Cloud Gateway

Spring Cloud Gateway provides a library for building an API Gateway on top of Spring WebFlux. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.

Features

Spring Cloud Gateway features:

  • Built on Spring Framework 5, Project Reactor and Spring Boot 2.0
  • Able to match routes on any request attribute.
  • Predicates and filters are specific to routes.
  • Circuit Breaker integration.
  • Spring Cloud DiscoveryClient integration
  • Request Rate Limiting
  • Path Rewriting

Built on Spring Framework 5, Project Reactor and Spring Boot 2.0

  • Project Reactor 
    Reactive systems have certain characteristics that make them ideal for low-latency, high-throughput workloads. Project Reactor and the Spring portfolio work together to enable developers to build enterprise-grade reactive systems that are responsive, resilient, elastic, and message-driven.
  • Spring-boot
    Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”. We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need minimal Spring configuration.

Match routes on any request attribute

The Spring Cloud Gateway uses routes to process requests to downstream services. In this blog, we route all of our requests to HTTPBin. Routes can be configured a number of ways, but we use the Java API provided by the Gateway.
To get started, create a new Bean of type RouteLocator in Application.java.

@Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder) {
return builder.routes().build();
}

The myRoutes method takes in a RouteLocatorBuilder that can be used to create routes. In addition to creating routes, RouteLocatorBuilder lets you add predicates and filters to your routes so that you can route handle based on certain conditions as well as alter the request/response as you see fit.

Predicates and filters 

  • Predicate: This is a Java 8 Function Predicate. The input type is a Spring Framework ServerWebExchange. This lets you match on anything from the HTTP request, such as headers or parameters.
  • Filter: These are instances of GatewayFilter that have been constructed with a specific factory. Here, you can modify requests and responses before or after sending the downstream request.

Circuit Breaker integration

Now we can do something a little more interesting. Since the services behind the Gateway could potentially behave poorly and affect our clients, we might want to wrap the routes we create in circuit breakers. You can do so in the Spring Cloud Gateway by using the Resilience4J Spring Cloud CircuitBreaker implementation. This is implemented through a simple filter that you can add to your requests. We can create another route to demonstrate this.

To use this filter you need to add the reactive Resilience4J CircuitBreaker dependency to your classpath.

pom.xml

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>

build.gradle

implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j")

Spring Cloud DiscoveryClient integration

You can configure the gateway to create routes based on services registered with a DiscoveryClient compatible service registry.

To enable this, set spring.cloud.gateway.discovery.locator.enabled=true and make sure a DiscoveryClient implementation (such as Netflix Eureka, Consul, or Zookeeper) is on the classpath and enabled.

Request Rate Limiting

Rate limiting is a technique to control the rate by which an API or a service is consumed. In a distributed system, no better option exists than to centralize configuring and managing the rate at which consumers can interact with APIs. Only those requests within a defined rate would make it to the API. Any more would raise an HTTP “Many requests” error.

link to rate limit image

Path Rewriting

Going back to this article’s main subject, let’s see how to define a route that rewrites the incoming URL before sending it to the backend. For example, suppose that given an incoming request of the form /api/v1/customer/*, the backend URL should be http://v1.customers/api/*. Here, we’re using “*” to represent “anything beyond this point”.

To create a configuration-based rewrite, we just need to add a few properties to the application’s configuration. Here, we’ll use YAML-based configuration for clarity, but this information could come from any supported PropertySource:

spring:
  cloud:
    gateway:
      routes:
      - id: rewrite_v1
        uri: ${rewrite.backend.uri:http://example.com}
        predicates:
        - Path=/v1/customer/**
        filters:
        - RewritePath=/v1/customer/(?<segment>.*),/api/$\{segment}

Let’s dissect this configuration. Firstly, we have the route’s id, which is just its identifiers. Next, we have the backend URI given by the uri property. Notice that only hostname/port are considered, as the final path comes from the rewrite logic.

The predicates property defines the conditions that must be met to activate this route. In our case, we use the Path predicate, which takes an ant-like path expression to match against the path of the incoming request.

Finally, the filters property has the actual rewrite logic. The RewritePath filter takes two arguments: a regular expression and a replacement string. The filter’s implementation works by simply executing the replaceAll() method on the request’s URI, using the provided parameters as arguments.

A caveat of the way that Spring handles configuration files is we can’t use the standard ${group} replacement expression, as Spring will think it is a property reference and try to replace its value. To avoid this, we need to add a backslash between the “$” and “{” characters that will be removed by the filter implementation before using it as the actual replacement expression.

Written by 

Abid Khan is a Lead Consultant at Knoldus Inc., postgraduate (MCA), and having 5+ years of experience in JavaSE, JavaEE, ORM framework, Spring, Spring-boot, RESTful Web Services, Kafka, MQTT, Rabbitmq, Docker, Redis, MySQL, Maven, GIT, etc. He is a well-developed professional with a prolific track record of designing, testing, and monitoring software as well as upgrading the existing programs.