Spring Cloud step-by-step (part 4)
Tags: spring, cloud, clouddiscovery
Published: 2018-06-28 23:51:08

---
title: Spring Cloud step-by-step (part 4)
published: true
description: Using service discovery in Java code
tags: spring,cloud,cloud discovery
---

This is a continuation of previous blog posts: 
 - [Spring Cloud step-by-step (part 1)](https://dev.to/piczmar_0/spring-cloud-step-by-step-part-1-1670)
 - [Spring Cloud step-by-step (part 2)](https://dev.to/piczmar_0/spring-cloud-step-by-step-part-2-12o2)
 - [Spring Cloud step-by-step (part 3)](https://dev.to/piczmar_0/spring-cloud-step-by-step-part-3-4jeg)

This time I will show you how to use Eureka discovery client to query other services without knowing their URLs.

In [previous post](https://dev.to/piczmar_0/spring-cloud-step-by-step-part-3-4jeg) we've seen how to configure Spring Cloud service discovery.

We used this for discovery of Config Server. It was handled automagically by Spring, but we have not seen how to call other services manually from java code (e.g. with RestTemplate).

Let's add another microservice which will use Pricing Service to get the price which user has to pay for renting an item.

Let's call it Rental Service.

It will have an API for renting an item for particular period and will return a price for rental.
The API will work this way:

```
curl -H 'Content-Type:application/json' http://localhost/v1/rentals/{id}/charges
```
Where {id} is an id of rental. We will not create an API to create rentals for now. To demonstrate calling another service we will just pass any {id} and the API will respond with hard-coded value, like:

```
{"price" : "1231.00"}
```

Our Spring Cloud system will now consist of the services as in the image below:

![Spring Cloud system](https://thepracticaldev.s3.amazonaws.com/i/z5gyp01la0ajbu1otofz.png)



There are different ways of using service discovery: 
1. With `org.springframework.cloud.client.discovery.DiscoveryClient`
2. With client-side load balancer called [Ribbon](https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html)
3. With [Feign](https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html) REST client

In this post I will concentrate on the first example and show the others in separate posts.

## Using EurekaClient API
`com.netflix.discovery.EurekaClient` is an implementation of `DiscoveryClient` by Netflix.

In the new service which we can create similarly we created other Spring Cloud services, we will add new dependency in `pom.xml`:

```xml
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
			<version>1.4.2.RELEASE</version>
		</dependency>
```

We also need to add annotation on main class: `@EnableEurekaClient`.

Finally, some configuration to let Eureka client know where discovery server is - in `bootsrap.yaml` add:

```
eureka:
  client:
    serviceUrl:
      defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
  instance:
    preferIpAddress: true
```

This means we expect server at `http://localhost:8761/eureka` but it can be also resolved from an environment variable `EUREKA_URI` e.g. in production environment.

When to use `preferIpAddress` property? When we want our application to register in Eureka server by IP and not hostname (see explanation [here](https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-eureka-server.html#spring-cloud-eureka-server-prefer-ip-address)).

Now we can use `EurekaClient` in new controller, e.g we could list all available services like this:

```java

import com.example.rental.rentalservice.v1.dto.RentalChargesResponse;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.shared.Application;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.Iterator;
import java.util.List;

@RestController
@RequestMapping(path = "/v1")
public class RentalController {

    private final EurekaClient eurekaClient;

    public RentalController(EurekaClient eurekaClient) {
        this.eurekaClient = eurekaClient;
    }

    @RequestMapping(path = "/rentals/{id}/charges", method = RequestMethod.GET)
    public ResponseEntity getPossibleCharges(@PathVariable("id") String id) {

        eurekaClient.getApplications();
        Iterator i = eurekaClient.getApplications().getRegisteredApplications().iterator();

        while (i.hasNext()) {
            Application app = (Application) i.next();
            System.out.println(app.getName());
            
        }

        return new ResponseEntity<>(new RentalChargesResponse(BigDecimal.ZERO), HttpStatus.OK);
    }
}

```

When we start application and invoke endpoint with

```
curl localhost:8080/v1/rentals/123/charges
```

we would see in application logs

```
PRICING-SERVICE
CONFIG-SERVICE
RENTAL-SERVICE

```

So it returned also information about itself (`RENTAL-SERVICE`). There is only one instance of each service, but in real system there would be more, because we would like to support some fault tolerance and scale application.

I leave trying what else we could get from `EurekaClient` APIs to you, but let's finally see how to query the Pricing Service.
Here we go:

```java
@RequestMapping(path = "/rentals/{id}/charges", method = RequestMethod.GET)
public ResponseEntity getPossibleCharges(@PathVariable("id") String id) {

    InstanceInfo instance = eurekaClient.getNextServerFromEureka("pricing-service", false);
    ZonedDateTime startTime = ZonedDateTime.now();
    ZonedDateTime endTime = startTime.plus(2, ChronoUnit.DAYS);
    HttpEntity<PriceRequest> request = new HttpEntity<>(
            new PriceRequest("vip", startTime, endTime)
    );
    PriceResponse response = restTemplate.postForObject(
        instance.getHomePageUrl() + "/v1/prices", request, PriceResponse.class);
    return new ResponseEntity<>(new RentalChargesResponse(response.getPrice()), HttpStatus.OK);
}
```

In the code above we are hardcoding input parameters for Pricing Service. We should first get the rental and extract these values from it, but since we do not have yet API to create rentals this is a shortcut.

In [the next post](https://dev.to/piczmar_0/spring-cloud-step-by-step-part-5-1g62) I will show you a simplier way to invoke endpoint using Eureka with [Ribbon](https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html).