Search code examples
spring-webfluxcqrsaxon

Axon Webflux QueryGateway how to handle Mono ResponseTypes


I'm trying to move our registration flow to a reactive setup with Spring Webflux as a POC, we've used AxonFramework to implement CQRS and ES. Our command flow was transformed fairly straight forward, but I'm having trouble transforming our query side.

The problems arrises when I try to transform a point-to-point query that returns a Mono response type, if I specify a Mono ResponseType I get the "No Handler found for [query] with response type"

Can anyone help me figure out how to handle queries with Mono ResponseTypes?

the query handler:

@QueryHandler
fun handleIsEmailUniqueQuery(query: IsEmailUniqueQuery): Mono<Boolean> =
        accountRepository.findAccountByEmail(query.email)
                .flatMap { Mono.just(true) }
                .switchIfEmpty(Mono.just(false))

the code calling the query gateway

fun validateEmailUnique(request: CreateRegistrationRequest): Mono<CreateRegistrationCommand> =
        Mono.fromFuture(queryGateway.query(IsEmailUniqueQuery(request.email), ResponseTypes.instanceOf(Mono::class.java)))
                .flatMap { mono ->  mono.cast(Boolean::class.java)}
                .flatMap { isEmailUnique ->
                    when (isEmailUnique) {
                        true -> Mono.just(CreateRegistrationCommand(request.email, request.password, UUID.randomUUID().toString()))
                        else -> Mono.error(DomainValidationException("ERR_EMAIL_UNIQUE"))
                    }
                }

Solution

  • So after re-reading the axon documentation I realized that I could return a CompletableFuture instead, after a small refactor it finally worked

    QueryHandler:

    @QueryHandler
    fun handleIsEmailUniqueQuery(query: IsEmailUniqueQuery): CompletableFuture<Boolean> =
            accountRepository.findAccountByEmail(query.email)
                    .flatMap { Mono.just(false) }
                    .switchIfEmpty(Mono.just(true))
                    .toFuture()
    

    code that calls the queryGateway

    fun validateEmailUnique(request: CreateRegistrationRequest): Mono<CreateRegistrationCommand> =
            Mono.fromFuture(queryGateway.query(IsEmailUniqueQuery(request.email), ResponseTypes.instanceOf(Boolean::class.java)))
                    .flatMap { isEmailUnique ->
                        when (isEmailUnique) {
                            true -> Mono.just(CreateRegistrationCommand(request.email, request.password, UUID.randomUUID().toString()))
                            else -> Mono.error(DomainValidationException("ERR_EMAIL_UNIQUE"))
                        }
                    }