Blog

Microservices: Consuming stateless services from Vaadin UIs

By  
Alejandro Duarte
Alejandro Duarte
·
On Feb 8, 2018 9:30:00 AM
·

In the previous articles of this series, 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 article, we’ll implement the first two functional microservices: A REST web service and a web UI for it.

Why do we need this?

Each service, or 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, they 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 consume the RESTful web service the same way customers can consume it from their systems.

Implementing a REST web service

Use 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, 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:

spring:
 application.name: biz-application
 cloud.config:
   discovery:
     enabled: true
     serviceId: config-server

eureka:
 client:
   serviceUrl:
     defaultZone: http://localhost:7001/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. If you do, every instance of biz-application will create a new database.

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;

   ... 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:

cd biz-application
mvn package
java -Dserver.port=9601 -jar target/biz-application-0.0.1-SNAPSHOT.jar

Point your browser to http://localhost:9601 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 Spring Initializr to create a new Spring Boot application named admin-application and include the Eureka Server, Config Client, Feign, HATEOAS, Vaadin, Validation, Hystrix, 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 {
    ...
}

Remove the application.properties file and create a new bootstrap.yml file similar to the one in the biz-application. Remember to use biz-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 id != null ? id.equals(company.id) : company.id == null;

    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }

    ... getters and setters ...
}

Create a Feign client that connects to 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 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 previous Feign client uses a client-side load balancer that consumes one instance of biz-application at a time in a round-robin fashion. Since the biz-application is a stateless service, it doesn’t need to worry about replicating any state among the running instances.

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>2.1.5</version>
</dependency>

Implement a new VaadinUI class as follows:

@SpringUI(path = "/")
public class VaadinUI extends UI {
    
    private final CompanyService companyService;

    public VaadinUI(CompanyService companyService) {
        this.companyService = companyService;
    }

    @Override
    protected void init(VaadinRequest request) {
        Label title = new Label("Companies");
        title.addStyleName(ValoTheme.LABEL_H2);

        GridCrud<Company> crud = new GridCrud<>(Company.class);
        crud.getGrid().setColumns("name", "twitterUsername");
        crud.getCrudFormFactory().setVisibleProperties("name", "twitterUsername");
        crud.getCrudFormFactory().setUseBeanValidation(true);
        crud.setFindAllOperation(() -> companyService.findAll().getContent());
        crud.setAddOperation(company -> companyService.add(company));
        crud.setUpdateOperation(company -> companyService.update(company.getId(), company));
        crud.setDeleteOperation(company -> companyService.delete(company.getId()));

        VerticalLayout mainLayout = new VerticalLayout(title, crud);
        setContent(mainLayout);
    }
}

The SpringUI annotation makes instances of the class Spring-managed beans. The path parameter configures the route you can use in the browser to see this UI. The init method uses Vaadin Framework to add a Label and a GridCrud component to the UI inside a VerticalLayout.

Compile the application, and run it by executing the following in the command line:

cd admin-application
mvn package
java -Dserver.port=9401 -jar target/admin-application-0.0.1-SNAPSHOT.jar

Point your browser to http://localhost:9401 to see the Vaadin UI in action:

We’ll continue exploring more topics about UIs with Vaadin Framework and microservices, fault tolerance, and load balancing in the next articles of this series.

Learn more about Vaadin for Spring Applications

Alejandro Duarte
Alejandro Duarte
Software Engineer and Developer Advocate at MariaDB Corporation. Author of Practical Vaadin (Apress), Data-Centric Applications with Vaadin 8 (Packt), and Vaadin 7 UI Design by Example (Packt). Passionate about software development with Java and open-source technologies. Contact him on Twitter @alejandro_du or through his personal blog at www.programmingbrain.com.
Other posts by Alejandro Duarte