From f879ab8cefc36044319874c7b9a57e6c6770c719 Mon Sep 17 00:00:00 2001 From: LiamGve Date: Sun, 5 Dec 2021 14:34:24 +0000 Subject: [PATCH] BAEL-5182 code for webclient status code handling article (#11373) * BAEL-5182 code for webclient status code handling article * BAEL-5182 code for webclient status code handling article * BAEL-5182 added different exceptions to make seperate examples clearer Co-authored-by: Liam Garvie --- .../status/WebClientStatusCodeHandler.java | 54 ++++++++++ .../status/exception/BadRequestException.java | 7 ++ .../exception/ServerErrorException.java | 7 ++ ...lientStatusCodeHandlerIntegrationTest.java | 98 +++++++++++++++++++ 4 files changed, 166 insertions(+) create mode 100644 spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/WebClientStatusCodeHandler.java create mode 100644 spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/BadRequestException.java create mode 100644 spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/ServerErrorException.java create mode 100644 spring-5-reactive-client/src/test/java/com/baeldung/webclient/WebClientStatusCodeHandlerIntegrationTest.java diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/WebClientStatusCodeHandler.java b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/WebClientStatusCodeHandler.java new file mode 100644 index 0000000000..9594ca32f1 --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/WebClientStatusCodeHandler.java @@ -0,0 +1,54 @@ +package com.baeldung.webclient.status; + +import com.baeldung.webclient.status.exception.BadRequestException; +import com.baeldung.webclient.status.exception.ServerErrorException; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +public class WebClientStatusCodeHandler { + + public static Mono getResponseBodyUsingExchangeFilterFunction(String uri) { + ExchangeFilterFunction errorResponseFilter = ExchangeFilterFunction + .ofResponseProcessor(WebClientStatusCodeHandler::exchangeFilterResponseProcessor); + return WebClient + .builder() + .filter(errorResponseFilter) + .build() + .post() + .uri(uri) + .retrieve() + .bodyToMono(String.class); + } + + public static Mono getResponseBodyUsingOnStatus(String uri) { + return WebClient + .builder() + .build() + .post() + .uri(uri) + .retrieve() + .onStatus( + HttpStatus.INTERNAL_SERVER_ERROR::equals, + response -> response.bodyToMono(String.class).map(ServerErrorException::new)) + .onStatus( + HttpStatus.BAD_REQUEST::equals, + response -> response.bodyToMono(String.class).map(BadRequestException::new)) + .bodyToMono(String.class); + } + + private static Mono exchangeFilterResponseProcessor(ClientResponse response) { + HttpStatus status = response.statusCode(); + if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) { + return response.bodyToMono(String.class) + .flatMap(body -> Mono.error(new ServerErrorException(body))); + } + if (HttpStatus.BAD_REQUEST.equals(status)) { + return response.bodyToMono(String.class) + .flatMap(body -> Mono.error(new BadRequestException(body))); + } + return Mono.just(response); + } +} diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/BadRequestException.java b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/BadRequestException.java new file mode 100644 index 0000000000..bf5c599805 --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/BadRequestException.java @@ -0,0 +1,7 @@ +package com.baeldung.webclient.status.exception; + +public class BadRequestException extends Exception { + public BadRequestException(String message) { + super(message); + } +} diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/ServerErrorException.java b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/ServerErrorException.java new file mode 100644 index 0000000000..7e97f17dff --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/ServerErrorException.java @@ -0,0 +1,7 @@ +package com.baeldung.webclient.status.exception; + +public class ServerErrorException extends Exception { + public ServerErrorException(String message) { + super(message); + } +} diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/webclient/WebClientStatusCodeHandlerIntegrationTest.java b/spring-5-reactive-client/src/test/java/com/baeldung/webclient/WebClientStatusCodeHandlerIntegrationTest.java new file mode 100644 index 0000000000..e491baf97a --- /dev/null +++ b/spring-5-reactive-client/src/test/java/com/baeldung/webclient/WebClientStatusCodeHandlerIntegrationTest.java @@ -0,0 +1,98 @@ +package com.baeldung.webclient; + +import com.baeldung.webclient.status.WebClientStatusCodeHandler; +import com.github.tomakehurst.wiremock.WireMockServer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.junit4.SpringRunner; +import reactor.core.publisher.Mono; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +@RunWith(SpringRunner.class) +public class WebClientStatusCodeHandlerIntegrationTest { + private String baseUrl; + private WireMockServer wireMockServer; + + @Before + public void setUp() { + wireMockServer = new WireMockServer(wireMockConfig().dynamicPort()); + wireMockServer.start(); + configureFor("localhost", wireMockServer.port()); + baseUrl = format("http://localhost:%s", wireMockServer.port()); + } + + @After + public void tearDown() { + wireMockServer.stop(); + } + + @Test + public void whenResponseIs2XX_thenBothStatusHandlerAndExchangeFilterReturnEqualResponses() { + stubPostResponse("/success", 200, "success"); + + Mono responseStatusHandler = WebClientStatusCodeHandler + .getResponseBodyUsingOnStatus(baseUrl + "/success"); + + Mono responseExchangeFilter = WebClientStatusCodeHandler + .getResponseBodyUsingExchangeFilterFunction(baseUrl + "/success"); + + assertThat(responseStatusHandler.block()) + .isEqualTo(responseExchangeFilter.block()) + .isEqualTo("success"); + } + + @Test + public void whenResponseIs500_thenBothStatusHandlerAndExchangeFilterReturnEqualResponses() { + stubPostResponse("/server-error", 500, "Internal Server Error"); + + Mono responseStatusHandler = WebClientStatusCodeHandler + .getResponseBodyUsingOnStatus(baseUrl + "/server-error"); + + Mono responseExchangeFilter = WebClientStatusCodeHandler + .getResponseBodyUsingExchangeFilterFunction(baseUrl + "/server-error"); + + assertThatThrownBy(responseStatusHandler::block) + .isInstanceOf(Exception.class) + .hasMessageContaining("Internal Server Error"); + + assertThatThrownBy(responseExchangeFilter::block) + .isInstanceOf(Exception.class) + .hasMessageContaining("Internal Server Error"); + } + + @Test + public void whenResponseIs400_thenBothStatusHandlerAndExchangeFilterReturnEqualResponses() { + stubPostResponse("/client-error", 400, "Bad Request"); + + Mono responseStatusHandler = WebClientStatusCodeHandler + .getResponseBodyUsingOnStatus(baseUrl + "/client-error"); + + Mono responseExchangeFilter = WebClientStatusCodeHandler + .getResponseBodyUsingExchangeFilterFunction(baseUrl + "/client-error"); + + assertThatThrownBy(responseStatusHandler::block) + .isInstanceOf(Exception.class) + .hasMessageContaining("Bad Request"); + + assertThatThrownBy(responseExchangeFilter::block) + .isInstanceOf(Exception.class) + .hasMessageContaining("Bad Request"); + } + + private static void stubPostResponse(String url, int statusCode, String response) { + stubFor(post(urlEqualTo(url)).willReturn(aResponse() + .withStatus(statusCode) + .withBody(response))); + } +} \ No newline at end of file