I want to do the following via Spring WebFlux and a given REST-API:
The problem is that I cannot combine both actions to "one" Mono instance. My current implementation is insufficient, because it blocks the Mono instances to execute the api calls immediately insteaf of performing them reactive.
My non reactive implementation:
public Mono cleanUpUploadedFiles() {
WebClient webClient = this.getWebClient();
// get all files / directories
Mono<FilesOverview> filesOverviewMono = this.getResource("/files", FilesOverview.class);
FilesOverview filesOverview = filesOverviewMono.block(); // TODO: prevent blocking mono
// delete file / directory one by one
for (FileOverview file : filesOverview.getFiles()) {
ClientResponse clientResponse;
clientResponse = webClient
.delete()
.uri(String.format("/files/local/%s", file.getName()))
.exchange()
.block(); // TODO: prevent blocking mono
if (clientResponse == null) {
return Mono.error(new MyException(String.format("could not execute rest call to delete uploaded files with uuid %s", file.getName())));
}
HttpStatus clientResponseStatusCode = clientResponse.statusCode();
if (clientResponseStatusCode.isError()) {
return Mono.error(new MyException(String.format("cannot delete uploaded files with uuid %s", file.getName())));
}
}
return Mono.empty(); // TODO: return Mono instance performing everything reactive without blocking
}
How to perform the consecutive web requests in one Mono instance reactive?
You should chain all of your operations in order to create a reactive stream.
Usually you take the output of one operation and use it as input for another operation.
Project Reactor provides a lot of map
and flatMap
operators to accomplish this.
In your example you should retrieve the list of files and then map each element to the delete operation like this:
public Mono<Void> cleanUpUploadedFiles() {
return getResource("/files", FilesOverview.class) // Retrieve the file list
.flatMapIterable(FilesOverview::getFiles) // Create a Flux from the file list
.map(FileOverview::getName) // Map the file overview to the file name
.flatMap(this::deleteFile) // Delete the file
.then(); // Just return a Mono<Void>
}
private Mono<Void> deleteFile(String fileName) {
return getWebClient()
.delete()
.uri("/files/local/{fileName}", fileName)
.exchange() // Perform the delete operation
.onErrorMap(e -> new MyException(String.format("could not execute rest call to delete uploaded files with uuid %s", fileName))) // Handle errors
.map(ClientResponse::statusCode) // Map the response to the status code
.flatMap(statusCode -> {
// If the operation was not successful signal an error
if (statusCode.isError()) {
return Mono.error(new MyException(String.format("cannot delete uploaded files with uuid %s", fileName)));
}
// Otherwise return a Mono<Void>
return Mono.empty();
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With