Blog

Calling microservices from Vaadin: Can you use them together?

By  
Sebastian Kuehnau
Sebastian Kuehnau
·
On Feb 11, 2025 5:00:06 PM
·

We are often asked in our community forum, customer meetings, or conferences if Vaadin can be used with microservices. The short answer is: Yes, absolutely.

To address this topic, I created a demo application using Vaadin that includes views implemented in Flow and Hilla. In this article, I’ll briefly explain what microservices are, how they can be used, and how they can be integrated into Vaadin applications.

What is a microservice?

A microservice is a small, technical unit responsible for a specific task like a particular business process or a technical service. Microservices are loosely coupled and communicate via common protocols and defined interfaces. This architecture enables the development of decentralized infrastructures with autonomous service units, allowing independent development in a heterogeneous technical environment.

Why should you use microservices?

Here are several reasons why a microservice architecture makes sense:

  1. Resilience: The modular structure isolates faults, allowing services to be managed and deployed independently.
  2. Technological diversity: Development teams can choose the technology best suited to their task without being tied to a homogeneous environment.
  3. Scalability: Microservices can be independently scaled as they distribute tasks across various units.

How can you use Vaadin with microservices?

A Vaadin application can easily connect to microservices through technology-independent interfaces. Common communication methods include REST, messaging services, Websockets, or gRPC. The Java ecosystem offers various frameworks and libraries to facilitate integration, giving you great flexibility in choosing a communication protocol.

My colleague Marcus Hellberg created an example demonstrating the use of microservices from Hilla applications. I extended this example to show how microservices can be used not only with Hilla but also with Flow.

Demo: User and order services

The demo application includes two service interfaces that provide information about users and their orders. These services are implemented in separate Spring-Boot applications: user-service and order-service. Access to these data services is handled via REST and implemented in the Vaadin application using Spring’s WebClient in the MyApplicationService.

(created with Mermaid Live Editor)

In the MyApplicationService we are setting up a connection to the respective REST Service and calling the client with the according URI and Parameter. In the given example we are requesting a data body from the URI “/orders” for the parameter “/user” and convert them into a list of Order

public List<Order> getOrders(@Nullable Long userId) {
       WebClient orderClient = webClientBuilder.baseUrl(orderServiceUrl).build();
       var orders = orderClient.get()
               .uri("/orders/user/" + userId)
               .retrieve()
               .bodyToFlux(Order.class)
               .collectList()
               .block();

       return orders;
}

In the Vaadin application, I implemented a view in Flow (FlowView.java) and one in Hilla (hilla-view.tsx). Access to the interfaces of the two microservices is centralized in the CustomerService. Both the Hilla and the Flow views provide the same functionality:

  1. A ComboBox displays all users.
  2. After selecting a user, their corresponding orders are displayed in a Grid.

The method above can be called as an injected bean in the Java code of the FlowView:

public FlowView(CustomerService customerService) {
       grid = new Grid<>(CustomerService.Order.class);
       grid.setItems(customerService.getOrders(someUserId));
       grid.setColumns("product", "price");
       add(grid);
}

Using Hilla comes with the benefit of consuming typed interfaces, which means the counterpart interfaces of Java Bean are generated in TypeScript and directly accessible in your React code.

export default function HillaView() {
   const [orders, setOrders] = useState<Order[]>([]);

   function selectedUserChanged(
       e: ComboBoxSelectedItemChangedEvent<Customer>
   ) {
       CustomerService
             .getOrders(e.detail.value ? e.detail.value.id : undefined)
             .then(setOrders);
   }

   return (
       <Grid items={orders}>
           <GridColumn path="product" />
           <GridColumn path="price" />
       </Grid>
   );
}

You can find the full code for the demo application on GitHub

Extending the example

As a next step, you could integrate a PaymentService to handle payment processing. If additional services are introduced, a dedicated service discovery system such as Eureka could be integrated to manage them effectively.

How do microservices differ from microfrontends?

In recent years, there has been a trend toward microfrontends. This approach modularizes also the frontend and creates a fragmented application architecture. It enhances scalability and technical independence for developer teams. Hereby, you need to consider the additional technical overhead required for deployment.

Conclusion

Microservices offer a flexible, scalable, and resilient architecture, making them ideal for modern Java application development. Vaadin seamlessly integrates with Flow and Hilla into any microservice architecture, supporting all kinds of communication protocols.

The example presented in this article demonstrates how to build a Vaadin application that consumes information from multiple microservices. Check out the demo application with the complete code examples on GitHub.