Skip to content

Commit b585df3

Browse files
LiamGveLiam Garvie
andauthored
BAEL-5182 code for webclient status code handling article (eugenp#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 <[email protected]>
1 parent 81ff66c commit b585df3

4 files changed

Lines changed: 166 additions & 0 deletions

File tree

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.baeldung.webclient.status;
2+
3+
import com.baeldung.webclient.status.exception.BadRequestException;
4+
import com.baeldung.webclient.status.exception.ServerErrorException;
5+
import org.springframework.http.HttpStatus;
6+
import org.springframework.web.reactive.function.client.ClientResponse;
7+
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
8+
import org.springframework.web.reactive.function.client.WebClient;
9+
import reactor.core.publisher.Mono;
10+
11+
public class WebClientStatusCodeHandler {
12+
13+
public static Mono<String> getResponseBodyUsingExchangeFilterFunction(String uri) {
14+
ExchangeFilterFunction errorResponseFilter = ExchangeFilterFunction
15+
.ofResponseProcessor(WebClientStatusCodeHandler::exchangeFilterResponseProcessor);
16+
return WebClient
17+
.builder()
18+
.filter(errorResponseFilter)
19+
.build()
20+
.post()
21+
.uri(uri)
22+
.retrieve()
23+
.bodyToMono(String.class);
24+
}
25+
26+
public static Mono<String> getResponseBodyUsingOnStatus(String uri) {
27+
return WebClient
28+
.builder()
29+
.build()
30+
.post()
31+
.uri(uri)
32+
.retrieve()
33+
.onStatus(
34+
HttpStatus.INTERNAL_SERVER_ERROR::equals,
35+
response -> response.bodyToMono(String.class).map(ServerErrorException::new))
36+
.onStatus(
37+
HttpStatus.BAD_REQUEST::equals,
38+
response -> response.bodyToMono(String.class).map(BadRequestException::new))
39+
.bodyToMono(String.class);
40+
}
41+
42+
private static Mono<ClientResponse> exchangeFilterResponseProcessor(ClientResponse response) {
43+
HttpStatus status = response.statusCode();
44+
if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
45+
return response.bodyToMono(String.class)
46+
.flatMap(body -> Mono.error(new ServerErrorException(body)));
47+
}
48+
if (HttpStatus.BAD_REQUEST.equals(status)) {
49+
return response.bodyToMono(String.class)
50+
.flatMap(body -> Mono.error(new BadRequestException(body)));
51+
}
52+
return Mono.just(response);
53+
}
54+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.baeldung.webclient.status.exception;
2+
3+
public class BadRequestException extends Exception {
4+
public BadRequestException(String message) {
5+
super(message);
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.baeldung.webclient.status.exception;
2+
3+
public class ServerErrorException extends Exception {
4+
public ServerErrorException(String message) {
5+
super(message);
6+
}
7+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package com.baeldung.webclient;
2+
3+
import com.baeldung.webclient.status.WebClientStatusCodeHandler;
4+
import com.github.tomakehurst.wiremock.WireMockServer;
5+
import org.junit.After;
6+
import org.junit.Before;
7+
import org.junit.Test;
8+
import org.junit.runner.RunWith;
9+
import org.springframework.test.context.junit4.SpringRunner;
10+
import reactor.core.publisher.Mono;
11+
12+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
13+
import static com.github.tomakehurst.wiremock.client.WireMock.configureFor;
14+
import static com.github.tomakehurst.wiremock.client.WireMock.post;
15+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
16+
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
17+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
18+
import static java.lang.String.format;
19+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
20+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
21+
22+
@RunWith(SpringRunner.class)
23+
public class WebClientStatusCodeHandlerIntegrationTest {
24+
private String baseUrl;
25+
private WireMockServer wireMockServer;
26+
27+
@Before
28+
public void setUp() {
29+
wireMockServer = new WireMockServer(wireMockConfig().dynamicPort());
30+
wireMockServer.start();
31+
configureFor("localhost", wireMockServer.port());
32+
baseUrl = format("http://localhost:%s", wireMockServer.port());
33+
}
34+
35+
@After
36+
public void tearDown() {
37+
wireMockServer.stop();
38+
}
39+
40+
@Test
41+
public void whenResponseIs2XX_thenBothStatusHandlerAndExchangeFilterReturnEqualResponses() {
42+
stubPostResponse("/success", 200, "success");
43+
44+
Mono<String> responseStatusHandler = WebClientStatusCodeHandler
45+
.getResponseBodyUsingOnStatus(baseUrl + "/success");
46+
47+
Mono<String> responseExchangeFilter = WebClientStatusCodeHandler
48+
.getResponseBodyUsingExchangeFilterFunction(baseUrl + "/success");
49+
50+
assertThat(responseStatusHandler.block())
51+
.isEqualTo(responseExchangeFilter.block())
52+
.isEqualTo("success");
53+
}
54+
55+
@Test
56+
public void whenResponseIs500_thenBothStatusHandlerAndExchangeFilterReturnEqualResponses() {
57+
stubPostResponse("/server-error", 500, "Internal Server Error");
58+
59+
Mono<String> responseStatusHandler = WebClientStatusCodeHandler
60+
.getResponseBodyUsingOnStatus(baseUrl + "/server-error");
61+
62+
Mono<String> responseExchangeFilter = WebClientStatusCodeHandler
63+
.getResponseBodyUsingExchangeFilterFunction(baseUrl + "/server-error");
64+
65+
assertThatThrownBy(responseStatusHandler::block)
66+
.isInstanceOf(Exception.class)
67+
.hasMessageContaining("Internal Server Error");
68+
69+
assertThatThrownBy(responseExchangeFilter::block)
70+
.isInstanceOf(Exception.class)
71+
.hasMessageContaining("Internal Server Error");
72+
}
73+
74+
@Test
75+
public void whenResponseIs400_thenBothStatusHandlerAndExchangeFilterReturnEqualResponses() {
76+
stubPostResponse("/client-error", 400, "Bad Request");
77+
78+
Mono<String> responseStatusHandler = WebClientStatusCodeHandler
79+
.getResponseBodyUsingOnStatus(baseUrl + "/client-error");
80+
81+
Mono<String> responseExchangeFilter = WebClientStatusCodeHandler
82+
.getResponseBodyUsingExchangeFilterFunction(baseUrl + "/client-error");
83+
84+
assertThatThrownBy(responseStatusHandler::block)
85+
.isInstanceOf(Exception.class)
86+
.hasMessageContaining("Bad Request");
87+
88+
assertThatThrownBy(responseExchangeFilter::block)
89+
.isInstanceOf(Exception.class)
90+
.hasMessageContaining("Bad Request");
91+
}
92+
93+
private static void stubPostResponse(String url, int statusCode, String response) {
94+
stubFor(post(urlEqualTo(url)).willReturn(aResponse()
95+
.withStatus(statusCode)
96+
.withBody(response)));
97+
}
98+
}

0 commit comments

Comments
 (0)