Web Services

RESTful Web Service Discovery

1. Introduction

This is an in-depth article related to the discovery of Restful Web Service. Spring Boot framework has features to build applications. Spring Boot has features related to building rest services and unit testing the application. It has a eureka registry to lookup and discover the RESTful Web Services. The standard HATEOAS (Hypermedia As The Engine Of Application State) is used for discoverability of methods of the RESTful web services.

2. RESTful Web Service Discovery

2.1 Prerequisites

Java 8 or 9 is required on the Linux, windows, or Mac operating system. Maven 3.6.1 is required for building the spring and hibernate application.

2.2 Download

You can download Java 8 can be downloaded from the Oracle web site . Apache Maven 3.6.1 can be downloaded from Apache site. Spring framework’s latest releases are available from the spring website.

2.3 Setup

You can set the environment variables for JAVA_HOME and PATH. They can be set as shown below:

Setup for Java

JAVA_HOME="/desktop/jdk1.8.0_73"
export JAVA_HOME
PATH=$JAVA_HOME/bin:$PATH
export PATH

The environment variables for maven are set as below:

Environment Setup for Maven

JAVA_HOME=”/jboss/jdk1.8.0_73″
export M2_HOME=/users/bhagvan.kommadi/Desktop/apache-maven-3.6.1
export M2=$M2_HOME/bin
export PATH=$M2:$PATH

2.4 Building the application

2.4.1 Spring

You can start building Spring applications using the Spring Boot framework. Spring Boot has a minimal configuration of Spring. Spring Boot has features related to security, tracing, application health management, and runtime support for web servers. Spring configuration is done through maven pom.xml. The XML configuration is shown below:

Spring Configuration

<?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>
   
    <groupId>org.springframework</groupId>
    <artifactId>spring-helloworld</artifactId>
    <version>0.1.0</version>
   
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
    </parent>
   
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
   
    <properties>
        <java.version>1.8</java.version>
    </properties>
   
   
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
   
</project>

You can create a HelloWorldController class as the web controller. The class is annotated using @RestController. Rest Controller is used to handle requests in Spring Model View Controller framework. Annotation @RequestMapping is used to annotate the index() method. The code for the HelloWorldController class is shown below:

HelloWorld Controller

package helloworld;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
   
@RestController
public class HelloWorldController {
       
    @RequestMapping("/")
    public String index() {
        return "Hello World\n";
    }
       
}

HelloWorldApp is created as the Spring Boot web application. When the application starts, beans, ​and settings are wired up dynamically. They are applied to the application context. The code for HelloWorldApp class is shown below:HelloWorld App

HelloWorldApp

package helloworld;
import java.util.Arrays;
   
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
   
@SpringBootApplication
public class HelloWorldApp {
       
    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(HelloWorldApp.class, args);
           
        System.out.println("Inspecting the beans");
           
        String[] beans = ctx.getBeanDefinitionNames();
        Arrays.sort(beans);
        for (String name : beans) {
            System.out.println("Bean Name" +name);
        }
    }
   
}

Maven is used for building the application. The command below builds the application.

Maven Build Command

.
mvn package

The output of the executed command is shown below.

rest service discovery - Maven Build
Maven Build

The jar file spring-helloworld-0.1.0.jar is created. The following command is used for executing the jar file.

Run Command

.
java -jar target/spring-helloworld-0.1.0.jar

The output of the executed command is shown below.

rest service discovery - Spring Beans
Spring Beans

The curl command is invoked on the command line for the execution of the index method. The method returns a string “Hello World” text. @RestController aggregates the two annotations @Controller and @ResponseBody. This results in returning data. The output is shown below.

rest service discovery - Curl Command
Curl Command

2.5 Rest Web Service -Discovery

Let us look at the service registry and discovery techniques of the RESTFul web services.

2.5.1 Service Registry

Netflix Eureka service registry is used for registering the services and for the client to look up the service. The registry helps in load balancing of the clients and decoupling of the consumers from the service providers. Spring initializr is used for getting the dependencies for an application and creating a setup for the developer.

Maven pom.xml is created to build the service application and for execution. The xml configuration is attached below:

Maven pom.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>2.3.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>rest-discovery-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>rest-discovery-service</name>
	<description>Spring Rest Service</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
	</properties>

	<dependencies>
		<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>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</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>

	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
		</repository>
	</repositories>

</project>

Eureka Service registry is enabled by using the @EnableEurekaServer annotation in the service application. This registry annotation starts the Eureka Service registry.

Spring Boot Application

package org.javacodegeeks.discovery;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class ServiceRegistryAndDiscoveryApp {

	public static void main(String[] args) {
		SpringApplication.run(ServiceRegistryAndDiscoveryApp.class, args);
	}
}

application.properties is used for specifying the registry requirements. Application properties file is shown below:

application.properties

server.port=8761

eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

logging.level.com.netflix.eureka=OFF
logging.level.com.netflix.discovery=OFF

Maven is used for building the application. The command below builds the application.

Maven Build Command

mvn package

The output of the executed command is shown below.

Build – Output

apples-MacBook-Air:complete bhagvan.kommadi$ mvn package
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] rest-discovery-client                          [jar]
[INFO] rest-discovery-service                         [jar]
[INFO] rest-service-discovery                              [pom]
[INFO] 
[INFO] -------< org.javacodegeeks:rest-discovery-client >--------
[INFO] Building rest-discovery-client 0.0.1-SNAPSHOT  [1/3]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ service-registration-and-discovery-client ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ service-registration-and-discovery-client ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/complete/eureka-client/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ rest-discovery-client ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/complete/eureka-client/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ rest-discovery-client ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/eureka-client/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ rest-discovery-client ---
[INFO] 
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.javacodegeeks.client.ServiceRegistrationAndDiscoveryClientAppTests

Maven is used for executing the application. The command below runs the spring boot application related to the REST Service registry.

Maven Run Command

./mvnw spring-boot:run -pl eureka-service

The output of the executed command is shown below.

Execution – Output

apples-MacBook-Air:complete bhagvan.kommadi$ ./mvnw spring-boot:run -pl eureka-service
[INFO] Scanning for projects...
[INFO] 
[INFO] -------< org.javacodegeeks:rest-discovery-service  >-------
[INFO] Building rest-discovery-service 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] >>> spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) > test-compile @ rest-discovery-service >>>
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ rest-discovery-service ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ rest-discovery-service ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ service-registration-and-discovery-service ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/eureka-service/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ rest-discovery-service ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] <<< spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) < test-compile @ rest-discovery-service <<<
[INFO] 
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) @ rest--discovery-service ---
[INFO] Attaching agents: []

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.2.RELEASE)

2021-01-03 01:13:25.115  INFO 14770 --- [           main] o.j.d.ServiceRegistrationAndDiscoveryApp : No active profile set, falling back to default profiles: default
2021-01-03 01:13:26.593  INFO 14770 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=4003ae63-5f2b-32e6-ac7b-ce9fc58862ab
2021-01-03 01:13:27.052  INFO 14770 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8761 (http)
2021-01-03 01:13:27.072  INFO 14770 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-01-03 01:13:27.073  INFO 14770 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.37]
2021-01-03 01:13:27.231  INFO 14770 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-01-03 01:13:27.232  INFO 14770 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2086 ms
2021-01-03 01:13:27.399  WARN 14770 --- [           main] c.n.c.sources.URLConfigurationSource     : No URLs will be polled as dynamic configuration sources.
2021-01-03 01:13:27.399  INFO 14770 --- [           main] c.n.c.sources.URLConfigurationSource     : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2021-01-03 01:13:27.421  INFO 14770 --- [           main] c.netflix.config.DynamicPropertyFactory  : DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration@3971f0fe
2021-01-03 01:13:27.819  WARN 14770 --- [           main] o.s.boot.actuate.endpoint.EndpointId     : Endpoint ID 'service-registry' contains invalid characters, please migrate to a valid format.
2021-01-03 01:13:28.020  INFO 14770 --- [           main] c.s.j.s.i.a.WebApplicationImpl           : Initiating Jersey application, version 'Jersey: 1.19.1 03/11/2016 02:08 PM'
2021-01-03 01:13:29.178  WARN 14770 --- [           main] o.s.c.n.a.ArchaiusAutoConfiguration      : No spring.application.name found, defaulting to 'application'
2021-01-03 01:13:29.179  WARN 14770 --- [           main] c.n.c.sources.URLConfigurationSource     : No URLs will be polled as dynamic configuration sources.
2021-01-03 01:13:29.179  INFO 14770 --- [           main] c.n.c.sources.URLConfigurationSource     : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2021-01-03 01:13:29.570  INFO 14770 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-01-03 01:13:30.786  INFO 14770 --- [           main] o.s.cloud.commons.util.InetUtils         : Cannot determine local hostname
2021-01-03 01:13:32.222  INFO 14770 --- [           main] o.s.cloud.commons.util.InetUtils         : Cannot determine local hostname
2021-01-03 01:13:33.226  INFO 14770 --- [           main] o.s.cloud.commons.util.InetUtils         : Cannot determine local hostname
2021-01-03 01:13:33.260  WARN 14770 --- [           main] ockingLoadBalancerClientRibbonWarnLogger : You already have RibbonLoadBalancerClient on your classpath. It will be used by default. As Spring Cloud Ribbon is in maintenance mode. We recommend switching to BlockingLoadBalancerClient instead. In order to use it, set the value of `spring.cloud.loadbalancer.ribbon.enabled` to `false` or remove spring-cloud-starter-netflix-ribbon from your project.
2021-01-03 01:13:33.329  INFO 14770 --- [           main] o.s.c.n.eureka.InstanceInfoFactory       : Setting initial instance status as: STARTING
2021-01-03 01:13:33.571  INFO 14770 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2021-01-03 01:13:33.605  INFO 14770 --- [           main] o.s.c.n.e.s.EurekaServiceRegistry        : Registering application UNKNOWN with eureka with status UP
2021-01-03 01:13:33.609  INFO 14770 --- [      Thread-11] o.s.c.n.e.server.EurekaServerBootstrap   : Setting the eureka configuration..
2021-01-03 01:13:33.610  INFO 14770 --- [      Thread-11] o.s.c.n.e.server.EurekaServerBootstrap   : Eureka data center value eureka.datacenter is not set, defaulting to default
2021-01-03 01:13:33.611  INFO 14770 --- [      Thread-11] o.s.c.n.e.server.EurekaServerBootstrap   : Eureka environment value eureka.environment is not set, defaulting to test
2021-01-03 01:13:33.643  INFO 14770 --- [      Thread-11] o.s.c.n.e.server.EurekaServerBootstrap   : isAws returned false
2021-01-03 01:13:33.644  INFO 14770 --- [      Thread-11] o.s.c.n.e.server.EurekaServerBootstrap   : Initialized server context
2021-01-03 01:13:33.667  INFO 14770 --- [      Thread-11] e.s.EurekaServerInitializerConfiguration : Started Eureka Server
2021-01-03 01:13:33.679  INFO 14770 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8761 (http) with context path ''
2021-01-03 01:13:33.681  INFO 14770 --- [           main] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 8761
2021-01-03 01:13:34.688  INFO 14770 --- [           main] o.s.cloud.commons.util.InetUtils         : Cannot determine local hostname
2021-01-03 01:13:34.711  INFO 14770 --- [           main] o.j.d.ServiceRegistrationAndDiscoveryApp : Started ServiceRegistrationAndDiscoveryApp in 13.08 seconds (JVM running for 13.895)
2021-01-03 01:13:44.938  INFO 14770 --- [nio-8761-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-01-03 01:13:44.939  INFO 14770 --- [nio-8761-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-01-03 01:13:44.957  INFO 14770 --- [nio-8761-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 18 ms
^C2021-01-03 01:15:40.159  INFO 14770 --- [extShutdownHook] o.s.c.n.e.s.EurekaServiceRegistry        : Unregistering application UNKNOWN with eureka with status DOWN
2021-01-03 01:15:40.268  INFO 14770 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  02:23 min
[INFO] Finished at: 2021-01-03T01:15:40+05:30
[INFO] ------------------------------------------------------------------------
apples-MacBook-Air:complete bhagvan.kommadi$

The second application (the client application) needs the Eureka Server and Eureka Discovery Client dependencies.

Maven pom.xml is created to build the application and for execution. The xml configuration is attached below:

Maven pom.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>2.3.2.RELEASE</version>
		<relativePath/> < >
	</parent>
	<groupId>org.javacodegeeks</groupId>
	<artifactId>rest-discovery-client</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>rest-discovery-client</name>
	<description>Spring Rest Client </description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</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>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</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>

	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
		</repository>
	</repositories>

</project>

Now client code needs to be developed. The service client will have @EnableDiscoveryClient annotation for Netflix Eureka Discovery client implementation. Service client code is shown below:

Service Client Application

package org.javacodegeeks.client;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@EnableDiscoveryClient
@SpringBootApplication
public class ServiceRegistrationAndDiscoveryClientApp {

	public static void main(String[] args) {
		SpringApplication.run(ServiceRegistrationAndDiscoveryClientApp.class, args);
	}
}

@RestController
class ServiceInstanceController {

	@Autowired
	private DiscoveryClient discoveryClient;

	@RequestMapping("/service-instances/{applicationName}")
	public List serviceInstancesByApplicationName(
			@PathVariable String applicationName) {
		return this.discoveryClient.getInstances(applicationName);
	}
}

eureka-client registered is specified in the bootstrap.properties. bootstrap.properties is shown below:

bootstrap.properties

spring.application.name=rest-service-client

Below is the command to execute the Service client application.

bootstrap.properties

./mvnw spring-boot:run -pl eureka-client

The output of the executed command is shown below.

Build – Output

apples-MacBook-Air:complete bhagvan.kommadi$ ./mvnw spring-boot:run -pl eureka-client
[INFO] Scanning for projects...
[INFO] 
[INFO] -------< org.javacodegeeks:rest-discovery-client >--------
[INFO] Building rest-discovery-client 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] >>> spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) > test-compile @ rest-discovery-client >>>
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ rest-discovery-client ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ rest-discovery-client ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/complete/eureka-client/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ rest-discovery-client ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/eureka-client/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ rest-discovery-client ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/eureka-client/target/test-classes
[INFO] 
[INFO] <<< spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) < test-compile @ rest-discovery-client <<<
[INFO] 
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) @ rest-discovery-client ---
[INFO] Attaching agents: []

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.2.RELEASE)

2021-01-03 01:13:58.121  INFO 14841 --- [           main] ServiceRegistrationAndDiscoveryClientApp : No active profile set, falling back to default profiles: default
2021-01-03 01:13:59.204  INFO 14841 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=cfe10556-feff-30ac-80c4-d8cc75409c7f
2021-01-03 01:13:59.530  INFO 14841 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-01-03 01:13:59.540  INFO 14841 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-01-03 01:13:59.540  INFO 14841 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.37]
2021-01-03 01:13:59.662  INFO 14841 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-01-03 01:13:59.662  INFO 14841 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1521 ms
2021-01-03 01:13:59.798  WARN 14841 --- [           main] c.n.c.sources.URLConfigurationSource     : No URLs will be polled as dynamic configuration sources.
2021-01-03 01:13:59.798  INFO 14841 --- [           main] c.n.c.sources.URLConfigurationSource     : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2021-01-03 01:13:59.808  INFO 14841 --- [           main] c.netflix.config.DynamicPropertyFactory  : DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration@2fc2a205
2021-01-03 01:13:59.866  WARN 14841 --- [           main] o.s.boot.actuate.endpoint.EndpointId     : Endpoint ID 'service-registry' contains invalid characters, please migrate to a valid format.
2021-01-03 01:14:00.979  INFO 14841 --- [           main] o.s.cloud.commons.util.InetUtils         : Cannot determine local hostname
2021-01-03 01:14:01.049  WARN 14841 --- [           main] c.n.c.sources.URLConfigurationSource     : No URLs will be polled as dynamic configuration sources.
2021-01-03 01:14:01.049  INFO 14841 --- [           main] c.n.c.sources.URLConfigurationSource     : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2021-01-03 01:14:01.282  INFO 14841 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-01-03 01:14:02.512  INFO 14841 --- [           main] o.s.cloud.commons.util.InetUtils         : Cannot determine local hostname
2021-01-03 01:14:03.823  INFO 14841 --- [           main] o.s.cloud.commons.util.InetUtils         : Cannot determine local hostname
2021-01-03 01:14:03.856  WARN 14841 --- [           main] ockingLoadBalancerClientRibbonWarnLogger : You already have RibbonLoadBalancerClient on your classpath. It will be used by default. As Spring Cloud Ribbon is in maintenance mode. We recommend switching to BlockingLoadBalancerClient instead. In order to use it, set the value of `spring.cloud.loadbalancer.ribbon.enabled` to `false` or remove spring-cloud-starter-netflix-ribbon from your project.
2021-01-03 01:14:03.912  INFO 14841 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2021-01-03 01:14:03.957  INFO 14841 --- [           main] o.s.c.n.eureka.InstanceInfoFactory       : Setting initial instance status as: STARTING
2021-01-03 01:14:04.055  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : Initializing Eureka in region us-east-1
2021-01-03 01:14:04.445  INFO 14841 --- [           main] c.n.d.provider.DiscoveryJerseyProvider   : Using JSON encoding codec LegacyJacksonJson
2021-01-03 01:14:04.445  INFO 14841 --- [           main] c.n.d.provider.DiscoveryJerseyProvider   : Using JSON decoding codec LegacyJacksonJson
2021-01-03 01:14:04.588  INFO 14841 --- [           main] c.n.d.provider.DiscoveryJerseyProvider   : Using XML encoding codec XStreamXml
2021-01-03 01:14:04.588  INFO 14841 --- [           main] c.n.d.provider.DiscoveryJerseyProvider   : Using XML decoding codec XStreamXml
2021-01-03 01:14:04.892  INFO 14841 --- [           main] c.n.d.s.r.aws.ConfigClusterResolver      : Resolving eureka endpoints via configuration
2021-01-03 01:14:04.923  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : Disable delta property : false
2021-01-03 01:14:04.923  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : Single vip registry refresh property : null
2021-01-03 01:14:04.923  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : Force full registry fetch : false
2021-01-03 01:14:04.923  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : Application is null : false
2021-01-03 01:14:04.923  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : Registered Applications size is zero : true
2021-01-03 01:14:04.923  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : Application version is -1: true
2021-01-03 01:14:04.924  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : Getting all instance registry info from the eureka server
2021-01-03 01:14:05.208  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : The response status is 200
2021-01-03 01:14:05.211  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : Starting heartbeat executor: renew interval is: 30
2021-01-03 01:14:05.215  INFO 14841 --- [           main] c.n.discovery.InstanceInfoReplicator     : InstanceInfoReplicator onDemand update allowed rate per min is 4
2021-01-03 01:14:05.221  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : Discovery Client initialized at timestamp 1609616645219 with initial instances count: 0
2021-01-03 01:14:05.222  INFO 14841 --- [           main] o.s.c.n.e.s.EurekaServiceRegistry        : Registering application REST-SERVICE-CLIENT with eureka with status UP
2021-01-03 01:14:05.224  INFO 14841 --- [           main] com.netflix.discovery.DiscoveryClient    : Saw local status change event StatusChangeEvent [timestamp=1609616645223, current=UP, previous=STARTING]
2021-01-03 01:14:05.226  INFO 14841 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_REST-SERVICE-CLIENT/localhost:rest-service-client: registering service...
2021-01-03 01:14:05.284  INFO 14841 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-01-03 01:14:05.286  INFO 14841 --- [           main] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 8080
2021-01-03 01:14:05.336  INFO 14841 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_REST-SERVICE-CLIENT/localhost:rest-service-client - registration status: 204
2021-01-03 01:14:06.297  INFO 14841 --- [           main] o.s.cloud.commons.util.InetUtils         : Cannot determine local hostname
2021-01-03 01:14:06.320  INFO 14841 --- [           main] ServiceRegistrationAndDiscoveryClientApp : Started ServiceRegistrationAndDiscoveryClientApp in 11.053 seconds (JVM running for 11.884)
2021-01-03 01:14:15.010  INFO 14841 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-01-03 01:14:15.011  INFO 14841 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-01-03 01:14:15.024  INFO 14841 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 12 ms
2021-01-03 01:14:35.226  INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : Disable delta property : false
2021-01-03 01:14:35.231  INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : Single vip registry refresh property : null
2021-01-03 01:14:35.232  INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : Force full registry fetch : false
2021-01-03 01:14:35.232  INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : Application is null : false
2021-01-03 01:14:35.232  INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : Registered Applications size is zero : true
2021-01-03 01:14:35.232  INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : Application version is -1: false
2021-01-03 01:14:35.232  INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : Getting all instance registry info from the eureka server
2021-01-03 01:14:35.408  INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : The response status is 200
^C2021-01-03 01:15:43.115  INFO 14841 --- [extShutdownHook] o.s.c.n.e.s.EurekaServiceRegistry        : Unregistering application REST-SERVICE-CLIENT with eureka with status DOWN
2021-01-03 01:15:43.118  WARN 14841 --- [extShutdownHook] com.netflix.discovery.DiscoveryClient    : Saw local status change event StatusChangeEvent [timestamp=1609616743118, current=DOWN, previous=UP]
2021-01-03 01:15:43.118  INFO 14841 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_REST-SERVICE-CLIENT/localhost:rest-service-client: registering service...
2021-01-03 01:15:43.179 ERROR 14841 --- [nfoReplicator-0] c.n.d.s.t.d.RedirectingEurekaHttpClient  : Request execution error. endpoint=DefaultEndpoint{ serviceUrl='http://localhost:8761/eureka/}

You can access the apps registered in the eureka server at : http://localhost:8761/eureka/apps/. The output is shown below:

rest service discovery - Eureka Apps Registered
Eureka Apps Registered

You can access the services registered in the eureka server at : http://localhost:8080/service-instances/rest-service-client. The output is shown below:

rest service discovery - Service Instances
Service Instances

2.5.2 HATEOAS

HATEOAS is Hypermedia As The Engine of Application state constraint. It is related to the discoverability of methods on the resource from Hypermedia Hypertext helps in replacing the documentation through the conversation. The HATEOAS representation helps in describing the API usage for clients. .The example for HATEOAS implementation can be accessed at this link.

3. Download the Source Code

Download
You can download the full source code of this example here: RESTful Web Service Discovery

Bhagvan Kommadi

Bhagvan Kommadi is the Founder of Architect Corner & has around 20 years’ experience in the industry, ranging from large scale enterprise development to helping incubate software product start-ups. He has done Masters in Industrial Systems Engineering at Georgia Institute of Technology (1997) and Bachelors in Aerospace Engineering from Indian Institute of Technology, Madras (1993). He is member of IFX forum,Oracle JCP and participant in Java Community Process. He founded Quantica Computacao, the first quantum computing startup in India. Markets and Markets have positioned Quantica Computacao in ‘Emerging Companies’ section of Quantum Computing quadrants. Bhagvan has engineered and developed simulators and tools in the area of quantum technology using IBM Q, Microsoft Q# and Google QScript. He has reviewed the Manning book titled : "Machine Learning with TensorFlow”. He is also the author of Packt Publishing book - "Hands-On Data Structures and Algorithms with Go".He is member of IFX forum,Oracle JCP and participant in Java Community Process. He is member of the MIT Technology Review Global Panel.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button