
Consuming stateless services
In the previous part of this tutorial, we focused on developing orchestration services to enable microservices. We implemented a Discovery Server to let applications consume services without knowing their exact location, and a Configuration Server to allow microservices to run in multiple environments without any modifications in the microservices themselves.
In this chapter, we’ll implement the first two functional microservices: A REST web service and a web UI for it.
Why do we need this?
Each microservice is typically developed and operated by independent development teams. The whole application is formed by several independently deployable services running in their own processes, which enables continuous delivery of single-purpose services. In short, microservices can be implemented, maintained, and deployed independently by separate development teams.
Although microservices are developed more or less independently, during runtime they do depend on other services to fulfill their function. In this example, we are using a well-known communication mechanism: RESTful web services.
Suppose we have two independent teams. The first one is developing a RESTful web service that allows customers to consume data from their systems. The second one is developing a web application to allow customers to consume data using a web UI in the browser. It makes sense to let the web UI use the RESTful web service the same way customers can use it from their systems.
Implementing a REST web service
Use the Spring Initializr to create a new Spring Boot application named biz-application
and include the Eureka Discovery, Config Client, JPA, Rest Repositories, Rest Repositories HAL browser, Hystrix, Retry, Aspects, Actuator, and DevTools (optional) dependencies:

Open up the BizApplication
class and activate the discovery client by using the following annotations:
@SpringBootApplication
@EnableDiscoveryClient
public class BizApplication {
...
}
Remove the application.properties
file and create a new bootstrap.yml
file with the following content:
server.port: 9001
spring:
application.name: biz-application
cloud.config:
discovery:
enabled: true
serviceId: config-server
fail-fast: true
retry:
initialInterval: 2000
maxAttempts: 30
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8001/eureka/
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1
This configures the application for using the Discovery and Configuration servers. The rest of the configuration comes from the Configuration Server which in turn is read from GitHub, or your local Git repository, depending on your configuration. The default configuration from GitHub includes a connection to a file-based H2 database located in the h2-database
directory inside your home directory. You cannot use an in-memory database with this example if you want to replicate the biz-application
microservice since every instance of biz-application
would create a new database.
Implementing a REST web service
Implement a simple domain class with JPA annotations, to configure the persistence to the database, as follows:
@Entity
public class Company {
@Id
@GeneratedValue
private Long id;
@NotNull
@Size(min = 1)
private String name;
@NotNull
@Size(min = 1)
private String twitterUsername;
... hashCode, equals, setters and getters ...
}
Define a repository interface and expose it a REST web service by marking it with the @RepositoryRestResource
annotation:
@RepositoryRestResource
public interface CompanyRepository extends CrudRepository<Company, Long> {
}
You don’t need to implement this interface. Spring will implement it at runtime.
Make sure the discovery-server
and config-server
applications are running and then compile and run the application by executing the following on the command line (or equivalent run configuraion in your IDE):
cd biz-application mvn package java -jar target/biz-application-0.0.1-SNAPSHOT.jar
Point your browser to http://localhost:9001 to see the HAL Browser for Spring Data Rest. This is a tool that allows you to navigate the web service for testing purposes. Try the /companies
endpoint by typing it in the text field in the Explorer section and click the Go! button:
Consuming a REST web service
Use the Spring Initializr to create a new Spring Boot application named admin-application
and include the Eureka Server, Config Client, Feign, HATEOAS, Vaadin, Validation, Hystrix, Retry, Aspects, Actuator, and DevTools (optional) dependencies:

Open up the AdminApplication
class and activate the discovery client, circuit breaker, Feign clients, and hypermedia support by using the following annotations:
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
@EnableFeignClients
@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class AdminApplication {
...
}
Since the web service uses Hypermedia Application Language (HAL), an specification that describes a generic structure for RESTful resources, you have to define the following bean in the client:
@Bean
public Module halModule() {
return new Jackson2HalModule();
}
Remove the application.properties
file and create a new bootstrap.yml
file similar to the one in the biz-application
. Remember to use admin-application
as the name of the application. The default configuration from GitHub configures a client-side load balancer with Ribbon and a circuit breaker with Hystrix.
Create a simple domain class as follows:
public class Company implements Serializable {
private Long id;
@NotNull
@Size(min = 1)
private String name;
@NotNull
@Size(min = 1)
private String twitterUsername;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Company company = (Company) o;
return Objects.equals(id, company.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
... getters and setters ...
}
Create a Feign client that consumes the web service provided by the biz-application
microservice:
@FeignClient(name = "${biz-application.name:null}")
public interface CompanyService {
@RequestMapping("/companies")
Resources<Company> findAll();
@RequestMapping(value = "/companies", method = RequestMethod.POST)
Company add(@RequestBody Company company);
@RequestMapping(value = "/companies/{id}", method = RequestMethod.PUT)
Company update(@PathVariable("id") Long id, @RequestBody Company company);
@RequestMapping(value = "/companies/{id}", method = RequestMethod.DELETE)
void delete(@PathVariable("id") Long id);
}
Notice how thanks to the Discovery Server, we can use the name of the application serving the web service (biz-application
) instead of a hardcoded URL. This allows the team developing the biz-application
to deploy their microservice anywhere. This also allows them to replicate the application as many times as they want, without having to modify the clients of the service. The Feign client (CompanyService
) uses a client-side load balancer that consumes one instance of biz-application
at a time using a round-robin strategy. Since the biz-application
is a stateless service, it doesn’t need to worry about replicating any state among the replicas.
Implementing a web UI for a REST web service
Implementing a CRUD web UI for this service can be quickly done with Vaadin and the Crud UI add-on. Add the following dependency in the pom.xml file:
<dependency>
<groupId>org.vaadin.crudui</groupId>
<artifactId>crudui</artifactId>
<version>3.7.1</version>
</dependency>
Implement a new AdminView
class as follows:
@Route("")
public class AdminView extends VerticalLayout {
private GridCrud<Company> crud = new GridCrud<>(Company.class, new VerticalCrudLayout());
public AdminView() {
ReconnectDialogConfiguration configuration =
UI.getCurrent().getReconnectDialogConfiguration();
configuration.setDialogText("Please wait...");
configuration.setReconnectInterval(1000);
H2 title = new H2("Companies");
crud.getGrid().setColumns("name", "twitterUsername");
crud.getCrudFormFactory().setVisibleProperties("name", "twitterUsername");
crud.getCrudFormFactory().setUseBeanValidation(true);
crud.setClickRowToUpdate(true);
crud.setUpdateOperationVisible(false);
crud.setFindAllOperation(() -> companyService.findAll().getContent());
crud.setAddOperation(company -> Services.getCompanyService().add(company));
crud.setUpdateOperation(company -> Services.getCompanyService().update(company.getId(), company));
crud.setDeleteOperation(company -> Services.getCompanyService().delete(company.getId()));
add(title, crud);
setMargin(false);
setHeight(null);
}
}
The Route
annotation makes instances of the class Spring-managed beans and exposes the route you can use in the browser to see this view. The constructor uses Vaadin Flow to add an H2
component and a GridCrud
component to the view (a VerticalLayout
).
Compile the application, and run it by executing the following in the command line (or equivalent run configuration in your IDE):
cd admin-application mvn package java -Dserver.port=9401 -jar target/admin-application-0.0.1-SNAPSHOT.jar
Point your browser to http://localhost:9101 to see the web application in action:

Comments (1)