2

I'm trying to learn Spring webflux & R2DBC. The one I try is simple use case:

  1. have a book table
  2. create an API (/books) that provides text stream and returning Flux<Book>
  3. I'm hoping when I hit /books once, keep my browser open, and any new data inserted to book table, it will send the new data to browser.

Scenario 2, still from book table:

  1. have a book table
  2. create an API (/books/count) that returning count of data in book as Mono<Long>
  3. I'm hoping when I hit /books/count once, keep my browser open, and any new data inserted /deleted to book table, it will send the new count to browser.

But it does not works. After I isnsert new data, no data sent to any of my endpoint.
I need to hit /books or /books/count to get the updated data.
I think to do this, I need to use Server Sent Events? But how to do this in and also querying data? Most sample I got is simple SSE that sends string every certain interval.

Any sample to do this?

Here is my BookApi.java

@RestController
@RequestMapping(value = "/books")
public class BookApi {

    private final BookRepository bookRepository;

    public BookApi(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    @GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Book> getAllBooks() {
        return bookRepository.findAll();
    }

    @GetMapping(value = "/count", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Mono<Long> count() {
        return bookRepository.count();
    }
}

BookRepository.java (R2DBC)

import org.springframework.data.r2dbc.repository.R2dbcRepository;

public interface BookRepository extends R2dbcRepository<Book, Long> {
}

Book.java

@Table("book")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {

    @Id
    private Long id;

    @Column(value = "name")
    private String name;

    @Column(value = "author")
    private String author;

}
Timothy
  • 855
  • 1
  • 13
  • 29
  • `Mono` is one delayed item. When that delayed item is resolved and sent back to the client the subscription ends and the connection closes. If you need to send multiple items you need to return a flux. I do not have any sample, but i can tell you that you need to subscribe to an endpoint that returns a `Flux`. – Toerktumlare Oct 28 '20 at 00:11
  • This `Flux` could for instance use a Processor/Sink https://projectreactor.io/docs/core/release/reference/#processors So that when someone inserts an item, before they return this item, they trigger a function that will get the latest count from db, and place it in the sink, and the sink will then push the new value to everyone that subscribes. – Toerktumlare Oct 28 '20 at 00:11
  • This is a bit more on the more advanced side of things, and you need to understand the concept of a sink before you start using processors. I recommend running through the reactor examples here https://projectreactor.io/docs/core/release/reference/#producing of how you programatically create sequences that can generate items through a Flux. – Toerktumlare Oct 28 '20 at 00:15

2 Answers2

1

Use a Processor or Sink to handle the Book created event.

Check my example using reactor Sinks, and read this article for the details.

Or use a tailable Mongo document.

A tailable MongoDB document can do the work automatically, check the main branch of the same repos.

My above example used the WebSocket protocol, it is easy to switch to SSE, RSocket.

Hantsy
  • 8,006
  • 7
  • 64
  • 109
0

Below Post would help you to achieve your first requirement

Spring WebFlux (Flux): how to publish dynamically

Let me know , if that helps you

  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/33284497) – Rich Dec 01 '22 at 16:01