Build a Reactive Spring Boot REST API with RxJava: Step‑by‑Step Guide

Learn how to create a reactive REST API using Spring Boot and RxJava, covering prerequisite knowledge, required dependencies, CRUD endpoint definitions, service layer implementation with RxJava Single, and web controller integration, plus essential Maven setup and tips to avoid common HttpMediaNotAcceptableException errors.

Programmer DD
Programmer DD
Programmer DD
Build a Reactive Spring Boot REST API with RxJava: Step‑by‑Step Guide

This article demonstrates how to develop a reactive REST API with Spring Boot and RxJava, assuming you are already familiar with these technologies.

1. Prerequisite Knowledge

Before proceeding, ensure you can create a simple REST API using Spring Boot and RxJava. If not, refer to resources such as Baeldung for Spring Boot and AndroidHive for RxJava.

2. Reactive REST API

Define the following CRUD endpoints for a basic author‑book service:

[POST] /api/authors – add an author

[POST] /api/books – add a book

[PUT] /api/books/{bookId} – update a book by its ID

[GET] /api/books?limit={limit}&page={page} – paginate book list

[GET] /api/book/{bookId} – get book details by ID

[DELETE] /api/book/{bookId} – delete a book

3. Dependencies

Add the following Maven dependencies to pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.1.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <version>2.1.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>io.reactivex</groupId>
        <artifactId>rxjava</artifactId>
        <version>1.3.8</version>
    </dependency>
    <dependency>
        <groupId>io.reactivex</groupId>
        <artifactId>rxjava-reactive-streams</artifactId>
        <version>1.2.1</version>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.199</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
        <version>1.18.8</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <version>2.1.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <scope>test</scope>
        <version>2.25.0</version>
    </dependency>
</dependencies>

Note: Adding the dependencies on lines 19‑23 (the RxJava reactive‑streams and test libraries) is essential; otherwise you will encounter HttpMediaNotAcceptableException when invoking the reactive API.

4. Service Layer

Service methods return RxJava Single objects. Below is an example that adds a new book:

@Override
public Single<String> addBook(AddBookRequest addBookRequest) {
    return saveBookToRepository(addBookRequest);
}

private Single<String> saveBookToRepository(AddBookRequest addBookRequest) {
    return Single.create(singleSubscriber -> {
        Optional<Author> optionalAuthor = authorRepository.findById(addBookRequest.getAuthorId());
        if (!optionalAuthor.isPresent()) {
            singleSubscriber.onError(new EntityNotFoundException());
        } else {
            String addedBookId = bookRepository.save(toBook(addBookRequest)).getId();
            singleSubscriber.onSuccess(addedBookId);
        }
    });
}

private Book toBook(AddBookRequest addBookRequest) {
    Book book = new Book();
    BeanUtils.copyProperties(addBookRequest, book);
    book.setId(UUID.randomUUID().toString());
    book.setAuthor(Author.builder().id(addBookRequest.getAuthorId()).build());
    return book;
}

5. Web Layer

The controller forwards requests to the service layer and returns a reactive response:

@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public Single<ResponseEntity<BaseWebResponse>> addBook(@RequestBody AddBookWebRequest addBookWebRequest) {
    return bookService.addBook(toAddBookRequest(addBookWebRequest))
            .subscribeOn(Schedulers.io())
            .map(s -> ResponseEntity.created(URI.create("/api/books/" + s))
                    .body(BaseWebResponse.successNoData()));
}

private AddBookRequest toAddBookRequest(AddBookWebRequest addBookWebRequest) {
    AddBookRequest addBookRequest = new AddBookRequest();
    BeanUtils.copyProperties(addBookWebRequest, addBookRequest);
    return addBookRequest;
}

6. Conclusion

The complete source code, including unit tests, is available on GitHub.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javareactive-programmingSpring BootREST APIRxJava
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.