I use Mono
s with ResponseEntity
s in my Webflux controllers in order to manipulate headers and other response info. For example:
@GetMapping("/{userId}")
fun getOneUser(@PathVariable userId: UserId): Mono<ResponseEntity<UserDto>> {
return repository.findById(userId)
.map(User::asDto)
.map { ResponseEntity.ok(it) }
.defaultIfEmpty(ResponseEntity.notFound().build())
}
@GetMapping
fun getAllUsers(): Flux<UserDto> {
return repository.findAllActive().map(User::asDto)
}
both works fine but there are cases where it is required to have ResponseEntity
in conjunction with Flux
as well. What should the response type be? Is it correct to use ResponseEntity<Flux<T>>
?
For example:
@GetMapping("/{userId}/options")
fun getAllUserOptions(@PathVariable userId: UserId): ??? {
return repository.findById(userId)
.flatMapIterable{ it.options }
.map { OptionDto.from(it) }
// if findById -> empty Mono then:
// return ResponseEntity.notFound().build() ?
// else:
// return the result of `.map { OptionDto.from(it) }` ?
}
The behaviour I'd like to achieve here is that getAllUserOptions returns 404
if repository.findById(userId)
is an empty Mono
, otherwise return user.options
as Flux
.
Update:
repository here is ReactiveCrudRepository
You can use by returning Mono with ResponseEntity
like this
public Mono<ResponseEntity<?>> oneRawImage(
@PathVariable String filename) {
// tag::try-catch[]
return imageService.findOneImage(filename)
.map(resource -> {
try {
return ResponseEntity.ok()
.contentLength(resource.contentLength())
.body(new InputStreamResource(
resource.getInputStream()));
} catch (IOException e) {
return ResponseEntity.badRequest()
.body("Couldn't find " + filename +
" => " + e.getMessage());
}
});
}
I have also example like this
public ResponseEntity<Mono<?>> newLive(@Valid @RequestBody Life life) {
Mono<Life> savedLive = liveRepository.save(life);
if (savedLive != null) {
return new ResponseEntity<>(savedLive, HttpStatus.CREATED);
}
return new ResponseEntity<>(Mono.just(new Life()), HttpStatus.I_AM_A_TEAPOT);
}
I dislike functional programming in the REST controllers.
Here is an example ReactiveController .
Use switchIfEmpty
to throw an exception in case the user doesn't exist:
return repository
.findById(userId)
.switchIfEmpty(Mono.error(NotFoundException("User not found")))
.flatMapIterable{ it.options }
.map { OptionDto.from(it) }
Then with an exception handler translate it to a 404 response.
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