With more than two services, hard-coded URLs between them break as soon as a port or host changes. This guide sets up the trio I used in MD Store: a Eureka registry, a gateway, and OpenFeign clients.

1. Create the Eureka registry

Add the spring-cloud-starter-netflix-eureka-server dependency to a new Spring Boot app and enable the server:

@SpringBootApplication
@EnableEurekaServer
public class RegistryServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(RegistryServiceApplication.class, args);
    }
}
# registry-service/src/main/resources/application.yml
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false   # the registry doesn't register itself
    fetch-registry: false

2. Register each service

Add spring-cloud-starter-netflix-eureka-client to every business service and give it a name. The name, not the port, is how other services find it.

# product-service application.yml
spring:
  application:
    name: product-service
server:
  port: 0   # random free port: Eureka knows where it is
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

3. Create the gateway

A new app with spring-cloud-starter-gateway and the Eureka client. The lb:// scheme means “look the service up in Eureka and load-balance between its instances”.

# gateway-service application.yml
server:
  port: 8080
spring:
  application:
    name: gateway-service
  cloud:
    gateway:
      routes:
        - id: products
          uri: lb://product-service
          predicates:
            - Path=/api/products/**
        - id: orders
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

Recent Spring Cloud releases (2025.0 and later) moved these properties under spring.cloud.gateway.server.webflux.routes. If routes are ignored after an upgrade, check the property prefix first.

4. Route through the gateway

Clients now call one address, http://localhost:8080/api/products/42, and the gateway forwards to whichever product-service instance is registered. This is also the right place for cross-cutting concerns such as token validation, CORS and rate limiting.

5. Call services with OpenFeign

Inside the cluster, services call each other by name too. Add spring-cloud-starter-openfeign, annotate the application with @EnableFeignClients, and declare an interface:

@FeignClient(name = "product-service")
public interface ProductClient {
    @GetMapping("/api/products/{id}")
    ProductDto getProduct(@PathVariable("id") Long id);
}

Inject ProductClient into the order service and call getProduct(id) like a local method. Feign builds the HTTP request and Eureka resolves the address.

6. Check the registry

Open http://localhost:8761. Every running service should be listed under its application name. Start order: registry, then services, then the gateway; the gateway retries until the services appear.