WebClient is asynchronous/non-blocking HTTP Client, it is replacement of RestTemplate, Here we walk through how to create and use webClient.
Add Dependency
implementation 'org.springframework.boot:spring-boot-start-webflux'
The Steps for WebClient to send request and receive response is following:
- Create
WebClientinstance - Attach
postorgetmethod - Attach the
Headersection, usualcontent-typeand/orAuthorization. - Attach the
bodysection - Attach the
retrieveorexchangemethod if you want handle response - Attach
onStatusto handle404or500error - Attach the
subscriberto thebodyToXXXmethod, the webFlux is asynchronous method, so we need subsriber to handle the object asychronously.
1. Create Instance of WebClient
1.1 Three ways to create WebClient instance
WebClient webClient = new WebClient.create();
or create with URL:
WebClient webClient = new WebClient.create("http://127.0.0.1/some_link");
or with builder mode:
following define a content we will send is json
WebClient webClient = WebClient.builder()
.basheUrl("http://127.0.0.1/some_linke")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
in the builder mode, you can add defaulHeader and other information to the WebClient.
1.2 Insert filter() to log, modify the request and response
Inject ExchangeFilterFunction during the building to intercept the request, you can use this functio to log the request or modify them:
with lambda version:
WebClient client = WebClient.builder()
.filter((request, next) -> {
logger.info("Request {} : {}", request.method(), request.url());
return next.exchange(request);
})
.build();
with method:
WebClient client = WebClient.builder()
.filter(logRequest())
.build();
private ExchangeFilterFunction logRequest(){
return (request, next) -> {
logger.info("Request {} : {}", request.method(), request.url());
return next.exchange(request);
};
}
If you want to modify the request, you need use ClientRequest class to extract the request:
WebClient client = WebClient.builder()
.filter((request, next) -> {
ClientRequest filtered = ClientRequest.from(request)
.header("foo", "bar")
.build();
return next.exchange(filtered);
})
.build();
the above example show the intercept the request and add attribution to the header.
1.3 Intecept the response
use ofResponseProcessor() factory pattern to create response filters:
WebClient client = WebClient.builder()
.filter( response -> {
logger.info("Response status {}", response.statusCode());
return mono.just(response);
}
.build();
2. Send Request by get() or post()
use get() or post() to use different HTTP methods.
3. Attach header
You can define defaultHeader when you create webClient, you also can attache the defaultHeader after get() or post() method by use header() method:
webClient.get()
.uri("")
.header("Authorization", "Basic " + Base64Utils
.encodeToString((username + ":" + token).getBytes(UTF_8)))
This insert a token in the header for authorization.
4. Attach body
4.1 Type of Request/Response Body
WebFlux is part of Project Reactor, it is non-blocking, asynchronous framework. Since it is Asychronous, so response back from Server could be 0, 1 till n. So Spring WebFlux provide following 2 type of object to wrap the response:
Mono<T>which can be either return 0..1 response(s).Flux<T>which can be return 0..n response(s).
so if your service return 1 object, then use Mono<T>, if return List, then use Flux<T>
To send Mono<T> request body:
webClient.post().uri("").body(Mono.just(OBJECT_INSTANCE_VARIABLE), YOUR_OBJECT.class)
put your object instance in the just method and determine the class of your object.
To receive Mono<T> response body:
webClient.post().uri("").body(Mono.just(OBJECT_INSTANCE_VARIABLE), YOUR_OBJECT.class).retrieve().bodyToMono(YOUR_RESPONSE_OBJECT.class)
retrieve() is the method to handle response, and after retreive, we use bodyToMono method
4.2 Three ways to define body
a. use .body()
webClient.post().uri("").body(Mono.just(OBJECT_INSTANCE_VARIABLE), YOUR_OBJECT.class)
This is normal way.
b. use syncBody() (Deprecated)
This is shortcut version of body(), if you just have 1 object to send, you can use following format:
webClient.post().uri("").syncBody(OBJECT_INSTANCE_VARIABLE)
c. use BodyInserteres class to create BodyInserter and then pass it in body(), this is for those FormData, MultipartData (file upload) those special.
5. Handle Response by retrieve() or exchange()
After you send the request to server, you need to see the response, there are 2 ways to handle: retrieve() is simpler, if you want to more control on response, then you can use exchange() method. exchange() provide full access to repsonse’s headers and body.