API gateways play a crucial role in modern microservices architectures by serving as the centralized entry point for client requests. They can handle the routing requests to the appropriate microservices and it can often involve the request transformation to adapt the client requests to the specific requirements of downstream services. In this article, we will explain the concepts of routing and request the transformation within API gateways in the context of the Spring Cloud microservices.
Routing in an API Gateway can involve defining the paths that guide the requests to the correct microservices. Request transformation can include the changes to the requests before forwarding them such as adding headers, changing the request path, or modifying the query parameters.
Routing
API gateways can route the incoming requests to the appropriate microservices based on predefined rules or patterns. This routing can be based on various criteria such as the URL paths, HTTP headers, or request parameters.
Request Transformation
Client can requests need to be transformed before being the forwarded to the downstream microservices. This transformation might be involve the modifying the request headers, body contents or even the request method.
Key Terminologies:
- API Gateway: The centralized entry point for the client requests in the microservices architecture. It can handles the routing, request transformation, authentication, authorization and the other cross cutting request parameters or the other criteria.
- Netflix Eureka: The service discovery tool can provided by the Spring Cloud which allows the microservices to the register themselves and discover the other services within the ecosystem. API gateways often use the Eureka for the dynamically routing the requests to available microservices.
- Filtering: In Context of the API gateways, filtering refers to the process of the intercepting incoming requests or outgoing responses and performing the actions such as authentication, logging, rate limiting or request transformation based on the predefined criteria.
- Routing Rules: Configurations defined within the API gateway to the determine how incoming the requests should be routed to the appropriate microservices. These rules can typically specify the criteria such as the URL patterns or request the header to match against incoming requests.
- Service Registration: The process by which the microservices register themselves with the service registry upon the startup. This can allows the API gateway and the other services to the dynamically discover and communicate with the registered microservices.
Implementation of Routing and Request Transformation in API Gateways in Spring Cloud Microservices
Below is the implementation to route and request transformation in API gateways in Spring Cloud Microservices.
Create the Gateway-Service
Step 1: Create a spring project using spring initializer and add the below dependencies.
Dependencies:
- Spring Web
- Spring Dev Tools
- Lombok
- Spring Cloud Routing
After creating the Spring project, the file structure will be like below.

Step 2: Open application.properties file and rename it to application.yml. Then, add the following YAML code for configuring the server port and API routing and eureka client configuration of the application.
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
- id: service_a_route
uri: lb://service-a
predicates:
- Path=/service-a/**
filters:
- AddRequestHeader=X-Request-Service, ServiceA
- id: service_b_route
uri: lb://service-b
predicates:
- Path=/service-b/**
filters:
- AddRequestHeader=X-Request-Service, ServiceB
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
Step 3: Create the RouteConfig Configuration class.
Go to src > org.example.gatewayservice > config > RouteConfig and put the below code.
Java
package org.example.gatewayservice.config;
import org.example.gatewayservice.fliter.RequestFilter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RouteConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("service_a_route", r -> r.path("/service-a/**")
.filters(f -> f.filter(new RequestFilter())
.addRequestHeader("X-Request-Service", "ServiceA"))
.uri("lb://service-a"))
.route("service_b_route", r -> r.path("/service-b/**")
.filters(f -> f.filter(new RequestFilter())
.addRequestHeader("X-Request-Service", "ServiceB"))
.uri("lb://service-b"))
.build();
}
}
The RouteConfig class in the gateway can configures the routes to the direct traffic to the service-a and service-b based on the URL path. Each service can checks for the custom header added by the gateway.
Step 4: Create the RequestFliter class.
Go to src > org.example.gatewayservice > filter > RequestFliter and put the below code.
Java
package org.example.gatewayservice.fliter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class RequestFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getRequest().mutate().header("X-Gateway-Filter", "RequestFilter").build();
return chain.filter(exchange);
}
}
Step 5: Create the CustomPredicate class.
Go to src > org.example.gatewayservice > predicate> CustomPredicate and put the below code.
Java
package org.example.gatewayservice.predicate;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.web.server.ServerWebExchange;
import java.util.function.Predicate;
public class CustomPredicate extends AbstractRoutePredicateFactory<CustomPredicate.Config> {
public static class Config {
// Configuration properties if any
}
public CustomPredicate() {
super(Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return exchange -> {
// Custom predicate logic
return exchange.getRequest().getHeaders().containsKey("X-Custom-Header");
};
}
}
Step 6: Open the main class add @EnableDiscoveryClient for activating the eureka client functionalities of the application.
Go to src > org.example.gatewayservice > GatewayServiceApplication and put the below code.
Java
package org.example.gatewayservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayServiceApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayServiceApplication.class, args);
}
}
pom.xml:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>gateway-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway-service</name>
<description>gateway-service</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2023.0.1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Step 7: Run the application
Once the Spring project successfully runs as a Spring application, it will start at port 8080.

The GatewayApplication is the entry point and the RouteConfig class can configures the routes and applies filters for request transformation. The RequestFilter adds the custom header to the each request.
Create the Eureka-Service
Step 1: Create a Spring project using Spring Initializr, and include the following dependencies:
Dependencies:
- Spring Web
- Eureka Server
- Spring Dev Tools
- Lombok
After creating the Spring project the folder structure will be like below:

Step 2: Open application.properties file and add the below code to configure the server port and Eureka server configurations for the project.
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:
enable-self-preservation: false
spring:
application:
name: eureka-server
Step 3: In the main class, include @EnableEurekaServer annotation to activate the Eureka server functionality of the application.
Java
package org.example.eurekaservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class, args);
}
}
pom.xml:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>eureka-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-service</name>
<description>eureka-service</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2023.0.1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Step 4: Run the application
Once completed the project after that run the application then it will be start at 8761.

Create the example-service-a microservice
Step 1: Create the spring project using spring initializer on creating the project add the below dependencies into the project.
Dependencies:
- Spring Web
- Netflix Eureka Server Client
- Spring Dev Tools
- Lombok
After the project creation done, it's structure will be like below image:

Step 2: Open the application.properties file and insert the below code to configure the server port and Eureka client configuration for the project.
server:
port: 8081
spring:
application:
name: service-a
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
Step 3: Create the ServiceAController class
Go to src > org.example.exampleservicea > ServiceAController and put the below code.
Java
package org.example.exampleservicea;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/service-a")
public class ServiceAController {
@GetMapping("/hello")
public String hello(@RequestHeader("X-Request-Service") String service) {
return "Hello from Service A! Header: " + service;
}
}
Step 4: In the main class, include @EnableEurekaServer annotation to activate the Eureka server functionality.
Java
package org.example.exampleservicea;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ExampleServiceAApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleServiceAApplication.class, args);
}
}
pom.xml:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>example-service-a</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>example-service-a</name>
<description>example-service-a</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2023.0.1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 5: Once the Spring project is completed and run as a Spring application successfully, it will start at port 8081.

Create the example-service-b microservice
Step 1: Create the spring project using spring initializer and add the below dependencies.
Dependencies:
- Spring Web
- Netflix Eureka Server Client
- Spring Dev Tools
- Lombok
Once the project is created, the folder structure will look like below:

Step 2: Open the application.properties file and insert the below code to configure the server port and Eureka client configuration for the project.
server:
port: 8082
spring:
application:
name: service-b
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
Step 3: Create the ServiceBController class.
Go to src > org.example.exampleserviceb > ServiceBController and put the below code.
Java
package org.example.exampleserviceb;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/service-b")
public class ServiceBController {
@GetMapping("/hello")
public String hello(@RequestHeader("X-Request-Service") String service) {
return "Hello from Service B! Header: " + service;
}
}
Step 4: In the main class, include the @EnableEurekaServer annotation to activate the Eureka server functionality.
Java
package org.example.exampleserviceb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ExampleServiceBApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleServiceBApplication.class, args);
}
}
pom.xml:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>example-service-b</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>example-service-b</name>
<description>example-service-b</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2023.0.1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 5: Once the Spring project is completed and run as a Spring application successfully, it will start at port 8082.

Once runs all the services of the gateway, eurekaservice, service-a, service-b of the Routing and Request Transformation in API Gateways.
Eureka Dashboard:
http://localhost:8761/eureka
Output:

Service A and Service B: These are two sample spring boot services that responds to the requests and each service can checks for the custom header added by the gateway service.
Example-Service-A API Endpoint:
GET http://localhost:8080/service-a/hello
Output:

Example-Service-B API Endpoint:
GET http://localhost:8080/service-b/hello
Output:

Each of the service will respond with the message indicating the header added by the gateway with the Eureka Configured and the gateway will correctly route the requests to the registered services.
Conclusion
By integrating with the Spring Cloud Gateway with Eureka for the service discovery, we can demonstrate effectively route and transform the requests in the microservices architecture. This setup can ensures that the gateway service can dynamically discover and route the requests to the backend services registered with the Eureka server.
Similar Reads
Java Spring Boot Microservices â Integration of Eureka and Spring Cloud Gateway
Microservices are small, loosely coupled distributed services. Microservices architecture evolved as a solution to the scalability, independently deployable, and innovation challenges with Monolithic Architecture. It provides us to take a big application and break it into efficiently manageable smal
5 min read
Java Spring Boot Microservices - Develop API Gateway Using Spring Cloud Gateway
The API Gateway Pattern in some cases stands for âBackend for frontendâ. It is basically the entry gate for taking entry into any application by an external source. The pattern is going on in a programmerâs mind while they are making the clientâs application. It acts as a medium between the client a
4 min read
API Composition and Aggregation with Spring Cloud Gateway in Java Microservices
API Composition and Aggregation is the critical pattern in the microservices architecture. It can enable combining the data from multiple microservices into a single response which is essential for reducing the number of client-side requests and improving the overall efficiency of the data retrieval
9 min read
Efficient Load Balancing and Metrics Monitoring in Spring Cloud Microservices
In Spring Microservices, services are often decentralized and distributed across multiple nodes. This architecture can enhance resilience and scalability but also introduces challenges such as efficient request distributions and performance monitoring. Load balancing and metrics monitoring are essen
6 min read
Service Discovery and Service Registry in Microservices
Microservices are small, loosely coupled distributed services. Microservices architecture evolved as a solution to the scalability, independently deployable, and innovation challenges with Monolithic Architecture. It provides us to take a big application and break it into efficiently manageable smal
5 min read
API Gateway Patterns in Microservices
In the Microservices Architecture, the API Gateway patterns stand out as a crucial architectural tool. They act as a central hub, managing and optimizing communication between clients and multiple microservices. These patterns simplify complexity, enhance security, and improve performance, making th
11 min read
How to Generate a New Spring Cloud Project in Spring Initializr?
Spring Initializr is a Web-based tool that generates the Spring Boot project structure. The spelling mistake in initializr is inspired by initializr. Modern IDEs have integrated Spring Initializr which provides the initial project structure. It is very easy for developers to select the necessary con
2 min read
Auto-Scaling Microservices with Eureka and Spring Boot
Auto-scaling Microservices with Eureka and Spring Boot involves leveraging Eureka for the service discovery and Spring Boot for building microservices that can dynamically scale based on the demand. This setup allows for efficient resource utilization and it can ensure that the system can handle var
8 min read
API Gateway Security Best Practices in Java Microservices
An API Gateway acts as a front-end for receiving API requests, enforcing throttling and security policies, passing requests to the back-end service, and then passing the response back to the requester. It sits between external clients and microservices, providing a unified entry point for multiple s
4 min read
Introduction to Messaging Queues in Spring Boot Microservices
In Microservices architecture, communication between the services is essential for achieving loose coupling and scalability. Messaging queues provide a reliable and asynchronous communication mechanism that can enable the seamless interaction between the microservices. Spring boot is a popular frame
8 min read