Преобразование Spring Webflux Mono в любую, желательно без блокировки?

Я использую Kotlin и Arrow и веб-клиент из spring-webflux, То, что я хотел бы сделать, это преобразовать экземпляр Mono в Either.

Either экземпляр создается путем вызова Either.right(..) когда ответ WebClient успешно или Either.left(..) когда WebClient возвращает ошибку.

То, что я ищу, это метод в Mono похож на Either.fold (..), где я могу отобразить успешный и ошибочный результат и вернуть другой тип, чем Mono, Примерно так (псевдокод не работает):

val either : Either<Throwable, ClientResponse> = 
                   webClient().post().exchange()
                                .fold({ throwable -> Either.left(throwable) },
                                      { response -> Either.right(response)})

Как идти?

2 ответа

Решение

Я не очень знаком с этой библиотекой Arrow и с типичным сценарием ее использования, поэтому здесь я буду использовать фрагменты Java.

Сначала я хотел бы сначала указать, что этот тип кажется блокирующим и не ленивым (в отличие от Mono). Переводя Mono этот тип означает, что вы сделаете свой код блокирующим и что вам не следует этого делать, например, в середине обработчика контроллера, или вы заблокируете весь свой сервер.

Это более или менее эквивалентно этому:

Mono<ClientResponse> response = webClient.get().uri("/").exchange();
// blocking; return the response or throws an exception
ClientResponse blockingResponse = response.block();

При этом, я думаю, вы должны быть в состоянии преобразовать Mono к этому типу путем вызова block() на это и try/catch блокировать вокруг него или превратить его сначала в CompletableFuture во-первых, как:

Mono<ClientResponse> response = webClient.get().uri("/").exchange();
Either<Throwable, ClientResponse> either = response
        .toFuture()
        .handle((resp, t) -> Either.fold(t, resp))
        .get();

Возможно, есть лучшие способы сделать это (особенно с помощью встроенных функций), но все они должны включать блокировку Mono на первом месте.

Здесь нет fold метод на Mono но вы можете достичь того же, используя два метода: map а также onErrorResume, Было бы что-то вроде этого:

val either : Either<Throwable, ClientResponse> = 
               webClient().post()
                          .exchange()
                          .map { Either.right(it) }
                          .onErrorResume { Either.left(it).toMono() }
Другие вопросы по тегам