Hilla Documentation

Reactive Endpoints

Tutorial on Using Project Reactor in Hilla Endpoints.
Important
Experimental Feature

Reactive Endpoints are an experimental feature, which means that its behavior, API, and look and feel might still change. In order to use Reactive Endpoints, they must be explicitly enabled with a feature flag. See the Feature Flag section for how to do this.

Although traditional server calls work fine in most cases, sometimes you need different tools for your job. Reactor is one of these. It can help you in streaming data to clients and fits well into a non-blocking application. Whenever the simple request-response pattern does not suit your needs, you might want to consider Reactor. Multi-user applications, infinite data streaming, and retries, are all good examples of what you can do with it.

If you want to pick up on Reactor, they have a curated learn page.

Although getting comfortable with creation of streaming, non-blocking applications requires some effort, Hilla allows you to take advantage of Reactor in literally minutes. We have an excellent blog article on reactive endpoints for you to get the basics.

A Working Example

Before describing the API details, let us try to write a basic application that can stream server time to the client. The purpose of this simple example will be to send the server time to all subscribed clients, with an interval of one second between each message.

Create a Hilla application as usual:

npx @vaadin/cli init --hilla --push flux-clock

Note the presence of the --push flag; this will enable push support, which is currently an experimental feature in Hilla. You can also enable it later, for example if you want to add it to an existing application.

Now, cd to start your new application and start it as usual:

cd flux-clock
./mvnw

Then, when the application shows in the browser, click on the Dev Tools icon in the bottom-right corner and then on Experimental features. Double-check that Push support in Hilla is enabled, or enable it if necessary.

Add Some Server Code…​

Open your application in your favorite IDE or editor.

First of all, create a new endpoint and name it ReactiveEndpoint. You can just put it inside HelloWorldEndpoint.java or in a package of your choice. This new endpoint will contain these two methods:

@AnonymousAllowed
public Flux<@Nonnull String> getClock() {
    return Flux.interval(Duration.ofSeconds(1))
            .onBackpressureDrop()
            .map(_interval -> new Date().toString());
}

@AnonymousAllowed
public EndpointSubscription<@Nonnull String> getClockCancellable() {
    return EndpointSubscription.of(getClock(), () -> {
        LOGGER.info("Subscription has been cancelled");
    });
}

You can click on the expand icon above the code snippet to get the whole file.

The first method, getClock(), creates a Flux that streams the server time each second. It uses onBackpressureDrop() to avoid saturation in case some messages cannot be sent to the client in real time. In this use case, it is perfectly fine to lose some messages.

The second method, getClockCancellable(), will return the same Flux, but wrapped in an EndpointSubscription, a Hilla-specific Flux wrapper which allows you to execute something on the server side if the subscription is cancelled by the client. In this example, a log message is produced.

…​ and Some Client Code

Let us use these methods in our client application. Create the frontend/views/reactive/reactive-view.ts file to add a new view. This will look like the default "Hello world" example, customized with the code that follows. Again, you can expand it if you prefer to get the whole file. You might have to fix some imports.

render() {
  return html`
    <vaadin-text-field label="Server time" .value=${this.serverTime}></vaadin-text-field>
    <vaadin-button @click=${this.toggleServerClock}>Toggle server clock</vaadin-button>
  `;
}

toggleServerClock() {
  if (this.subscription) {
    this.subscription.cancel();
    this.subscription = undefined;
  } else {
    (this.subscription = ReactiveEndpoint.getClockCancellable()).onNext((time) => {
      this.serverTime = time;
    });
  }
}

Then, add the new view to the router (frontend/routes.ts), by importing it with:

import './views/reactive/reactive-view';

and declaring it with:

  {
    path: 'reactive-clock',
    component: 'reactive-view',
    icon: 'la la-clock',
    title: 'Server Clock',
  },

just below the hello path.

You new view should now be available in the application page. When the Toggle server clock button is clicked, the time will appear in the text field and will update each second. You can stop it by clicking again.

A Quick Look at the API

The generated TypeScript endpoint methods return a Subscription<T> object, which offers these methods:

  • cancel() to cancel the subscription;

  • onNext() to get the next message in the Flux;

  • onError() to get errors that can happen in the Flux;

  • onComplete() to be informed when the Flux has no more messages to send;

  • context() to bind to the context, which allows the application to automatically close it when the view is detached.

Feature Flag

In order to use Reactive Endpoints, they must be explicitly enabled with a feature flag. There are two methods of doing this:

Using Vaadin Developer Tools

  1. Click on the Vaadin Developer Tools icon button in your running application

  2. Open the Experimental Features tab

  3. Enable the Push support in Hilla feature

  4. Restart the application.

Adding a Feature Flags Properties File

  1. Create a src/main/resources/vaadin-featureflags.properties file in your application folder

  2. Add the following content: com.vaadin.experimental.hillaPush=true

  3. Restart the application.