Understanding problems switchIfEmpty and switchIfEmpty

1.1k views Asked by At

I try to write web app using kotlin/webflux/r2dbc:postgresql But I have proplem. I can't understand why switchIfEmpty call if result of work hackerService.resetPassword not empty

Controller

@PostMapping("/reset/password/{link}", consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
    fun resetPassword(@PathVariable link: String, req: ResetPassword): Mono<ResponseEntity<String>> {
        return userservice.resetPassword(link, req)
                .map { ResponseEntity.ok("OK") }
                .switchIfEmpty(Mono.just(ResponseEntity.notFound().build()))
    }

Service

fun resetPassword(link: String, resetPassword: ResetPassword): Mono<Void> {
        BLEException.checkArgument(resetPassword.newPassword == resetPassword.checkPassword, PASSWORD_NOT_MATCH)
        return resetPasswordRepository.findByLink(link)
                .flatMap { updateAccount(it.userId, password = resetPassword.newPassword) }
                .flatMap { resetPasswordRepository.deleteByUserId(it.id!!) }
    }

Method updateAccount is setting new password and resetPasswordRepository.deleteByUserId drop row from table. And this method work, and I expecte not empty Mono as result of resetPassword

But finaly I have as result 404 error.

I would be glad for any help, thanks

2

There are 2 answers

0
Michael McFadyen On BEST ANSWER

If resetPasswordRepository is a spring data ReactiveCrudRepository, then the return type of all delete*() methods is Mono<Void>

Mono<Void> is the type of an empty Mono.

As a result, switchIsEmpty will always be invoked as the object returned from resetPassword is an empty Mono.

0
Chris On

two ways I can think of how to solve it as a follow up to this answer

  1. return a Mono.error instead of empty in the service and map the error to a ResponseStatusException in the controller
return resetPasswordRepository.findByLink(link)
    .switchIfEmpty(Mono.error(UserNotFound()))

  1. use the .then*() operation to map the result of delete* from Mono<Void> to something else, say the deleted entity. You'd need to change the result type of the service method, of course
    .flatMap { resetPasswordRepository.deleteByUserId(it.id!!).thenReturn(it) }