Discover how to integrate Spring Boot 3 API Gateway with Spring Cloud Netflix Eureka Server for seamless communication and microservices architecture.
An API Gateway is a crucial intermediary in microservices, serving as the single entry point for client requests. It acts as a gatekeeper, routing and load-balancing incoming traffic to the appropriate backend services. By centralizing authentication, authorization, and other cross-cutting concerns, the API Gateway simplifies the management and security of the developer applications.
The API Gateway is pivotal in facilitating communication between clients and the service instances registered with the Eureka server when working with Eureka Springs. By leveraging Eureka Springs’ service discovery capabilities, the API Gateway can dynamically route requests to the appropriate service instances, ensuring optimal load distribution and failover mechanisms.
Moreover, the API Gateway is a powerful tool for implementing cross-cutting concerns such as rate limiting, caching, and request transformation. This centralized approach enhances the developer application’s security and performance and promotes code reusability and maintainability.
Key Benefits.
- Simplified API Management: No more juggling multiple endpoints.
- Enhanced Security: Fortify your defenses with centralized authentication and authorization.
- Efficient Load Balancing: Distribute incoming traffic evenly, ensuring smooth sailing for your services.
Ready to get started? Dive in and experience the magic of Spring Boot API Gateway and Spring Cloud Netflix Eureka for yourself.
Set up the Eureka server and client.

Set up the API Gateway.
This example demonstrates the seamless integration of Eureka Springs, API Gateway, and Spring Boot, enabling us to quickly build scalable, fault-tolerant, and highly available applications.
1. Initial project with spring initializr
2. Add Dependencies.
<?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.3.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>api-gateway</artifactId> <version>0.0.1-SNAPSHOT</version> <name>api-gateway</name> <description>Demo project for Spring Boot</description> <url/> <licenses> <license/> </licenses> <developers> <developer/> </developers> <scm> <connection/> <developerConnection/> <tag/> <url/> </scm> <properties> <java.version>21</java.version> <spring-cloud.version>2023.0.3</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</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>
3. Next, the developer creates a Spring Boot application that will act as an application API Gateway, leveraging the power of Eureka Springs for service discovery.
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class ApiGatewayApplication { public static void main(String[] args) { SpringApplication.run(ApiGatewayApplication.class, args); } }
4. Configure application.properties
or application.yml
for API Gateway
server: port: 9090 spring: application: name: api-gateway cloud: gateway: discovery: locator: enabled: true lower-case-service-id: true routes: - id: eureka-client uri: lb://EUREKA-CLIENT predicates: - Path=/** eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ instance: lease-renewal-interval-in-seconds: 30 # Frequency (in seconds) at which the client sends heartbeats to the Eureka server lease-expiration-duration-in-seconds: 90 # Time (in seconds) after which the Eureka server considers the instance expired if no heartbeat is received management: endpoint: gateway: enabled: true endpoints: web: exposure: include: '*' logging: level: root: INFO org.springframework.cloud.gateway: DEBUG org.springframework.web: DEBUG reactor.netty: DEBUG
Configuration Explanation.
spring.cloud.gateway.discovery.locator.enabled
: Enables the use of service discovery to locate routes dynamically. When set to true
, Spring Cloud Gateway will discover routes using the services registered with Eureka.
spring.cloud.gateway.discovery.locator.lower-case-service-id
: When set to true
This converts all service IDs to lowercase. This can help avoid case-sensitivity issues when matching service IDs in a case-insensitive environment.
spring.cloud.gateway.routes
: Defines the static routes for the gateway. In this configuration, one route is defined.
eureka.client.service-url.defaultZone
: Specifies the URL of the Eureka server where the application should register itself and where it should send heartbeat messages. The defaultZone
point is the Eureka server URL.
eureka.instance.lease-renewal-interval-in-seconds
: Sets the frequency (in seconds) at which the application sends heartbeat messages to the Eureka server. This is set to 30
seconds, meaning the client will send a heartbeat every 30 seconds.
eureka.instance.lease-expiration-duration-in-seconds
: Defines the time (in seconds) after which the Eureka server will consider the instance as “down” or unavailable if it does not receive a heartbeat. It is set to 90
seconds. If the Eureka server doesn’t receive a heartbeat within this period, it will mark the instance as down and remove it from the registry.
management.endpoint.gateway.enabled
: Enables the Spring Cloud Gateway Actuator endpoints, allowing for monitoring and managing the gateway routes and filters through the /actuator/gateway
endpoint.
management.endpoints.web.exposure.include
: Specifies which actuator endpoints should be exposed over HTTP. The value '*'
Includes all available actuator endpoints, making them accessible via the management port (by default, the same as the application port).

1. Create a Dockerfile.
# Stage 1: Build the JAR file FROM maven:3.9.7-amazoncorretto-21 AS build WORKDIR /app COPY pom.xml . COPY src ./src RUN mvn clean package -DskipTests # Stage 2: Run the application FROM amazoncorretto:21-alpine VOLUME /tmp COPY --from=build /app/target/*.jar api-gateway.jar ENTRYPOINT ["java", "-jar", "/api-gateway.jar"]
2. Create a Docker compose file.
version: '3.8' services: api-gateway: build: context: . dockerfile: Dockerfile container_name: api-gateway environment: - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/ ports: - "9090:9090" networks: - eureka_eureka-network networks: eureka_eureka-network: external: true
3. The developer can check the network in Docker by following this command.
>docker network ls NETWORK ID NAME DRIVER SCOPE 2c7250cfbc7a bridge bridge local 1a78ba5571d4 eureka_eureka-network bridge local
4. The developer can inspect the network by following this command.
>docker inspect eureka_eureka-network [ { "Name": "eureka_eureka-network", "Id": "1a78ba5571d4fdd2c3a7b174f79626780f5082a33fcf7e576ef88e5705307f5a", "Created": "2024-09-02T11:35:30.757824047Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.24.0.0/16", "Gateway": "172.24.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "17c7a20ed0300de0b2f0827a8bfc48f6ed17898924b459fe859acc3440149ce4": { "Name": "eureka-eureka-client-2", "EndpointID": "bf683251bd12e76a55f16479072481d527941c4b7f3db5d1d53268733a4084e0", "MacAddress": "02:42:ac:18:00:05", "IPv4Address": "172.24.0.5/16", "IPv6Address": "" }, "2e7082ee05fd8f853628e352b570c1d3b040276e76ee810346186996fc0e478d": { "Name": "eureka-server", "EndpointID": "0cd0fd34acc274954e656cdb4a249ca92988c09040fdda64fdda04c882a9f266", "MacAddress": "02:42:ac:18:00:03", "IPv4Address": "172.24.0.3/16", "IPv6Address": "" }, "52475e2369a43b6d20cc231a0c53e5bfb424baef4a349434993b170a5f798301": { "Name": "api-gateway", "EndpointID": "91cf1ba80ac6457a29fe5b26efc050bb60aa61fc93f9bad3a3be76ae641127ad", "MacAddress": "02:42:ac:18:00:02", "IPv4Address": "172.24.0.2/16", "IPv6Address": "" }, "d40f061f7f3b6e12d961ae74c9a861e2a33fb89c20ecd110cda80a075ffcf984": { "Name": "eureka-eureka-client-1", "EndpointID": "6d0d6a56c7af45f1b8240b6ff68f2e223f1d37bf91c55d22056381a6eaba7523", "MacAddress": "02:42:ac:18:00:06", "IPv4Address": "172.24.0.6/16", "IPv6Address": "" }, "f64012185ccae36af3a89ac5beb448572155b4b01655749794839c786d32a8cc": { "Name": "eureka-eureka-client-3", "EndpointID": "7f2bd041f3c815a1440a65ad7066d474613da26154a373dddfc6892855020b42", "MacAddress": "02:42:ac:18:00:04", "IPv4Address": "172.24.0.4/16", "IPv6Address": "" } }, "Options": {}, "Labels": { "com.docker.compose.network": "eureka-network", "com.docker.compose.project": "eureka", "com.docker.compose.version": "2.29.1" } } ]
5. Execute the Docker command to start the API gateway.
>docker compose up -d
The -d
flag in the docker-compose up -d
Command stands for “detached mode.” When you run Docker Compose with the -d
flag, the containers start in the background, allowing you to continue using the terminal.
6. Check the image of the API gateway.
>docker images REPOSITORY TAG IMAGE ID CREATED SIZE api-gateway-api-gateway latest da7f5af74844 20 hours ago 367MB
7. Check the container of the API gateway.
>docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 52475e2369a4 api-gateway-api-gateway "java -jar /api-gate…" 20 hours ago Up 13 minutes 0.0.0.0:9090->9090/tcp api-gateway
Access the actuator gateway routes.
1. The developer can view the gateway by accessing the URL.
http://localhost:9090/actuator/gateway/routes

Issue.
When the developer accesses the actuator gateway routes, the gateway is not found or is a blank page. The developer should check your dependency.
artifactId should be “spring-cloud-starter-gateway”, not “spring-cloud-starter-gateway-mvc”. Do not use artifactId “spring-boot-starter-web” in the API gateway project.
When starting the API gateway server, this message will appear when the developer uses artifactId “spring-boot-starter-web” and artifactId “spring-cloud-starter-gateway” together.
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration$SpringMvcFoundOnClasspathConfiguration': Failed to instantiate [org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration$SpringMvcFoundOnClasspathConfiguration]: Constructor threw exception
Access the Eureka client from the API gateway.
1. The developer can access the Eureka client by accessing the URL.
>curl http://localhost:9090/hostname f64012185cca
Alternatively, windows Powershell.
> curl http://localhost:9090/hostname StatusCode : 200 StatusDescription : OK Content : d40f061f7f3b RawContent : HTTP/1.1 200 OK Content-Length: 12 Content-Type: text/plain;charset=UTF-8 Date: Tue, 03 Sep 2024 08:20:12 GMT d40f061f7f3b Forms : {} Headers : {[Content-Length, 12], [Content-Type, text/plain;charset=UTF-8], [Date, Tue, 03 Sep 2024 08:20:12 GMT]} Images : {} InputFields : {} Links : {} ParsedHtml : mshtml.HTMLDocumentClass RawContentLength : 12
2. The API gateway can access the Eureka client and return a response from the client.
Issue.
When the developer accesses the Eureka client and gets the message 503 Service Unavailable, the developer should check that the artifactId “spring-cloud-starter-loadbalancer” must be included in the dependency.
1. Response on Windows PowerShell without a load balancer.
> curl http://localhost:9090/hostname {"timestamp":"2024-09-03T08:25:29.982+00:00","path":"/hostname","status":503,"error":"Service Unavailable","requestId":"07c0cba7-1","message":"Unable to find instance for EUREKA-CLIENT","trace":"org.springframework.cloud.gateway.support.NotFoundException: 503 SERVICE_UNAVAILABLE \"Unable to find instance for EUREKA-CLIENT\"\r\n\tat org.springframework.cloud.gateway.support.NotFoundException.create(NotFoundException.java:45)\r\n\tSuppressed: The stacktrace has been enhanced by Reactor, refer to additional information below: \r\nError has been observed at the following site(s):\r\n\t*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]\r\n\t*__checkpoint ⇢ HTTP GET \"/hostname\" ...
2. Response on the Postman without a load balancer.
{ "timestamp": "2024-09-03T08:27:19.513+00:00", "path": "/hostname", "status": 503, "error": "Service Unavailable", "requestId": "4a06906b-1", "message": "Unable to find instance for EUREKA-CLIENT", "trace": ... }
Conclusion
The API Gateway acts as a unified entry point for clients, abstracting the complexities of the underlying microservices architecture. It offers a range of benefits, including routing, authentication, authorization, monitoring, load balancing, and protocol translation, ensuring a consistent and secure interface for clients.
Finally
By combining these powerful tools, the developer can unlock new application agility, scalability, and reliability levels. Whether building a small-scale project or a large-scale enterprise system, the Spring Boot ecosystem provides a solid foundation for embracing the microservices paradigm and delivering exceptional software solutions. The developer can improve the security of the Spring boot API gateway by using JSON Web Tokens (JWT) or performance by using a rate limiter.