From 68af2f59d3377b1a83409f509245b630cf27f746 Mon Sep 17 00:00:00 2001 From: Alexander Molochko Date: Tue, 23 Apr 2019 15:46:50 +0300 Subject: [PATCH 1/5] WebClient request with parameters --- .../SpringWebClientRequestsApp.java | 12 ++ .../WebClientRequestsTest.java | 151 ++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 spring-5-webflux/src/main/java/com/baeldung/spring/webclientrequests/SpringWebClientRequestsApp.java create mode 100644 spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsTest.java diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/webclientrequests/SpringWebClientRequestsApp.java b/spring-5-webflux/src/main/java/com/baeldung/spring/webclientrequests/SpringWebClientRequestsApp.java new file mode 100644 index 0000000000..314fe2fdf9 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/webclientrequests/SpringWebClientRequestsApp.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.webclientrequests; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringWebClientRequestsApp { + + public static void main(String[] args) { + SpringApplication.run(SpringWebClientRequestsApp.class, args); + } +} diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsTest.java new file mode 100644 index 0000000000..3055f1521d --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsTest.java @@ -0,0 +1,151 @@ +package com.baeldung.spring.webclientrequests; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFunction; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.DefaultUriBuilderFactory; +import reactor.core.publisher.Mono; + +import static org.mockito.Mockito.*; + +@RunWith(SpringRunner.class) +@WebFluxTest +public class WebClientRequestsTest { + + private static final String BASE_URL = "https://example.com"; + + private WebClient webClient; + + @Captor + private ArgumentCaptor argumentCaptor; + + private ExchangeFunction exchangeFunction; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + this.exchangeFunction = mock(ExchangeFunction.class); + ClientResponse mockResponse = mock(ClientResponse.class); + when(this.exchangeFunction.exchange(this.argumentCaptor.capture())).thenReturn(Mono.just(mockResponse)); + this.webClient = WebClient + .builder() + .baseUrl(BASE_URL) + .exchangeFunction(exchangeFunction) + .build(); + } + + @Test + public void whenUriComponentEncoding_thenQueryParamsNotEscaped() { + DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(BASE_URL); + factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.URI_COMPONENT); + this.webClient = WebClient + .builder() + .uriBuilderFactory(factory) + .baseUrl(BASE_URL) + .exchangeFunction(exchangeFunction) + .build(); + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/posts/") + .queryParam("title", "Baeldung") + .queryParam("authorId", "99") + .queryParam("date", "13/04/2019") + .build()) + .retrieve(); + verifyCalledUrl("/posts/?title=Baeldung&authorId=99&date=13/04/2019"); + } + + @Test + public void whenCallSimpleURI_thenURIMatched() { + this.webClient.get() + .uri("/posts") + .retrieve(); + verifyCalledUrl("/posts"); + } + + @Test + public void whenCallSinglePathSegmentUri_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/posts/{id}") + .build(2)) + .retrieve(); + verifyCalledUrl("/posts/2"); + } + + @Test + public void whenCallMultiplePathSegmentsUri_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/posts/{id}/comments/{commentId}") + .build(2, 13)) + .retrieve(); + verifyCalledUrl("/posts/2/comments/13"); + } + + @Test + public void whenCallSingleQueryParams_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/posts/") + .queryParam("title", "Baeldung") + .queryParam("authorId", "99") + .queryParam("date", "13/04/2019") + .build()) + .retrieve(); + verifyCalledUrl("/posts/?title=Baeldung&authorId=99&date=13/04/2019"); + } + + @Test + public void whenCallSingleQueryParamsPlaceholders_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/posts/") + .queryParam("title", "{title}") + .queryParam("authorId", "{authorId}") + .queryParam("date", "{date}") + .build("Baeldung", "99", "13/04/2019")) + .retrieve(); + verifyCalledUrl("/posts/?title=Baeldung&authorId=99&date=13%2F04%2F2019"); + } + + @Test + public void whenCallArrayQueryParamsBrackets_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/posts/") + .queryParam("tag[]", "Spring", "Kotlin") + .build()) + .retrieve(); + verifyCalledUrl("/posts/?tag%5B%5D=Spring&tag%5B%5D=Kotlin"); + } + + @Test + public void whenCallArrayQueryParams_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/posts/") + .queryParam("category", "Web", "Mobile") + .build()) + .retrieve(); + verifyCalledUrl("/posts/?category=Web&category=Mobile"); + } + + private void verifyCalledUrl(String relativeUrl) { + ClientRequest request = this.argumentCaptor.getValue(); + Assert.assertEquals(String.format("%s%s", BASE_URL, relativeUrl), request.url().toString()); + Mockito.verify(this.exchangeFunction).exchange(request); + verifyNoMoreInteractions(this.exchangeFunction); + } +} From 61f44f5c1790f3403df3b679d2260aa68483b128 Mon Sep 17 00:00:00 2001 From: Alexander Molochko Date: Wed, 24 Apr 2019 15:22:49 -0700 Subject: [PATCH 2/5] Change Test name --- ...ebClientRequestsTest.java => WebClientRequestsUnitTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/{WebClientRequestsTest.java => WebClientRequestsUnitTest.java} (99%) diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java similarity index 99% rename from spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsTest.java rename to spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java index 3055f1521d..62fca0ba9d 100644 --- a/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsTest.java +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java @@ -21,7 +21,7 @@ import static org.mockito.Mockito.*; @RunWith(SpringRunner.class) @WebFluxTest -public class WebClientRequestsTest { +public class WebClientRequestsUnitTest { private static final String BASE_URL = "https://example.com"; From 5adb5186f0bf56cf0e2ec05e74f0d6d6a751c4c4 Mon Sep 17 00:00:00 2001 From: Alexander Molochko Date: Thu, 25 Apr 2019 11:19:54 -0700 Subject: [PATCH 3/5] Add comma-separated example --- .../webclientrequests/WebClientRequestsUnitTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java index 62fca0ba9d..c1bab1ecf5 100644 --- a/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java @@ -131,6 +131,7 @@ public class WebClientRequestsUnitTest { verifyCalledUrl("/posts/?tag%5B%5D=Spring&tag%5B%5D=Kotlin"); } + @Test public void whenCallArrayQueryParams_thenURIMatched() { this.webClient.get() @@ -142,6 +143,17 @@ public class WebClientRequestsUnitTest { verifyCalledUrl("/posts/?category=Web&category=Mobile"); } + @Test + public void whenCallArrayQueryParamsComma_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/posts/") + .queryParam("category", String.join(",", "Web", "Mobile")) + .build()) + .retrieve(); + verifyCalledUrl("/posts/?category=Web,Mobile"); + } + private void verifyCalledUrl(String relativeUrl) { ClientRequest request = this.argumentCaptor.getValue(); Assert.assertEquals(String.format("%s%s", BASE_URL, relativeUrl), request.url().toString()); From 80514b2a8d936192869f17bdf79da123a43cfac8 Mon Sep 17 00:00:00 2001 From: Alexander Molochko Date: Fri, 26 Apr 2019 20:38:35 -0700 Subject: [PATCH 4/5] Change posts resource to products --- .../WebClientRequestsUnitTest.java | 187 +++++++++--------- 1 file changed, 94 insertions(+), 93 deletions(-) diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java index c1bab1ecf5..8919daa9fb 100644 --- a/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java @@ -45,6 +45,95 @@ public class WebClientRequestsUnitTest { .build(); } + + @Test + public void whenCallSimpleURI_thenURIMatched() { + this.webClient.get() + .uri("/products") + .retrieve(); + verifyCalledUrl("/products"); + } + + @Test + public void whenCallSinglePathSegmentUri_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/{id}") + .build(2)) + .retrieve(); + verifyCalledUrl("/products/2"); + } + + @Test + public void whenCallMultiplePathSegmentsUri_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/{id}/attributes/{attributeId}") + .build(2, 13)) + .retrieve(); + verifyCalledUrl("/products/2/attributes/13"); + } + + @Test + public void whenCallSingleQueryParams_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/") + .queryParam("name", "AndroidPhone") + .queryParam("color", "black") + .queryParam("deliveryDate", "13/04/2019") + .build()) + .retrieve(); + verifyCalledUrl("/products/?name=AndroidPhone&color=black&deliveryDate=13/04/2019"); + } + + @Test + public void whenCallSingleQueryParamsPlaceholders_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/") + .queryParam("name", "{title}") + .queryParam("color", "{authorId}") + .queryParam("deliveryDate", "{date}") + .build("AndroidPhone", "black", "13/04/2019")) + .retrieve(); + verifyCalledUrl("/products/?name=AndroidPhone&color=black&deliveryDate=13%2F04%2F2019"); + } + + @Test + public void whenCallArrayQueryParamsBrackets_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/") + .queryParam("tag[]", "Snapdragon", "NFC") + .build()) + .retrieve(); + verifyCalledUrl("/products/?tag%5B%5D=Snapdragon&tag%5B%5D=NFC"); + } + + + @Test + public void whenCallArrayQueryParams_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/") + .queryParam("category", "Phones", "Tablets") + .build()) + .retrieve(); + verifyCalledUrl("/products/?category=Phones&category=Tablets"); + } + + @Test + public void whenCallArrayQueryParamsComma_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/") + .queryParam("category", String.join(",", "Phones", "Tablets")) + .build()) + .retrieve(); + verifyCalledUrl("/products/?category=Phones,Tablets"); + } + @Test public void whenUriComponentEncoding_thenQueryParamsNotEscaped() { DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(BASE_URL); @@ -57,101 +146,13 @@ public class WebClientRequestsUnitTest { .build(); this.webClient.get() .uri(uriBuilder -> uriBuilder - .path("/posts/") - .queryParam("title", "Baeldung") - .queryParam("authorId", "99") - .queryParam("date", "13/04/2019") + .path("/products/") + .queryParam("name", "AndroidPhone") + .queryParam("color", "black") + .queryParam("deliveryDate", "13/04/2019") .build()) .retrieve(); - verifyCalledUrl("/posts/?title=Baeldung&authorId=99&date=13/04/2019"); - } - - @Test - public void whenCallSimpleURI_thenURIMatched() { - this.webClient.get() - .uri("/posts") - .retrieve(); - verifyCalledUrl("/posts"); - } - - @Test - public void whenCallSinglePathSegmentUri_thenURIMatched() { - this.webClient.get() - .uri(uriBuilder -> uriBuilder - .path("/posts/{id}") - .build(2)) - .retrieve(); - verifyCalledUrl("/posts/2"); - } - - @Test - public void whenCallMultiplePathSegmentsUri_thenURIMatched() { - this.webClient.get() - .uri(uriBuilder -> uriBuilder - .path("/posts/{id}/comments/{commentId}") - .build(2, 13)) - .retrieve(); - verifyCalledUrl("/posts/2/comments/13"); - } - - @Test - public void whenCallSingleQueryParams_thenURIMatched() { - this.webClient.get() - .uri(uriBuilder -> uriBuilder - .path("/posts/") - .queryParam("title", "Baeldung") - .queryParam("authorId", "99") - .queryParam("date", "13/04/2019") - .build()) - .retrieve(); - verifyCalledUrl("/posts/?title=Baeldung&authorId=99&date=13/04/2019"); - } - - @Test - public void whenCallSingleQueryParamsPlaceholders_thenURIMatched() { - this.webClient.get() - .uri(uriBuilder -> uriBuilder - .path("/posts/") - .queryParam("title", "{title}") - .queryParam("authorId", "{authorId}") - .queryParam("date", "{date}") - .build("Baeldung", "99", "13/04/2019")) - .retrieve(); - verifyCalledUrl("/posts/?title=Baeldung&authorId=99&date=13%2F04%2F2019"); - } - - @Test - public void whenCallArrayQueryParamsBrackets_thenURIMatched() { - this.webClient.get() - .uri(uriBuilder -> uriBuilder - .path("/posts/") - .queryParam("tag[]", "Spring", "Kotlin") - .build()) - .retrieve(); - verifyCalledUrl("/posts/?tag%5B%5D=Spring&tag%5B%5D=Kotlin"); - } - - - @Test - public void whenCallArrayQueryParams_thenURIMatched() { - this.webClient.get() - .uri(uriBuilder -> uriBuilder - .path("/posts/") - .queryParam("category", "Web", "Mobile") - .build()) - .retrieve(); - verifyCalledUrl("/posts/?category=Web&category=Mobile"); - } - - @Test - public void whenCallArrayQueryParamsComma_thenURIMatched() { - this.webClient.get() - .uri(uriBuilder -> uriBuilder - .path("/posts/") - .queryParam("category", String.join(",", "Web", "Mobile")) - .build()) - .retrieve(); - verifyCalledUrl("/posts/?category=Web,Mobile"); + verifyCalledUrl("/products/?name=AndroidPhone&color=black&deliveryDate=13/04/2019"); } private void verifyCalledUrl(String relativeUrl) { From 60c545f5fef9f401f8b1a87638edb87d481962cb Mon Sep 17 00:00:00 2001 From: Alexander Molochko Date: Sun, 28 Apr 2019 16:09:24 -0700 Subject: [PATCH 5/5] Update README file --- spring-5-webflux/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-5-webflux/README.md b/spring-5-webflux/README.md index 84c3d5a4ca..4345c8746b 100644 --- a/spring-5-webflux/README.md +++ b/spring-5-webflux/README.md @@ -2,3 +2,4 @@ - [Spring Boot Reactor Netty Configuration](https://www.baeldung.com/spring-boot-reactor-netty) - [How to Return 404 with Spring WebFlux](https://www.baeldung.com/spring-webflux-404) +- [WebClient request with parameters](https://www.baeldung.com/webclient-request-with-parameters)