WebClient etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
WebClient etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

23 Ekim 2023 Pazartesi

SpringWebFlux Transitioning from RestTemplate to WebClient in Spring Boot

GET
Örnek
Şöyle yaparız
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.getForEntity("http://example.com", String.class);


WebClient webClient = WebClient.create();
Mono<String> response = webClient.get()
    .uri("http://example.com")
    .retrieve()
    .bodyToMono(String.class);
response.subscribe(result -> System.out.println(result));
Handling Errors
Açıklaması şöyle
RestTemplate’s error handling occurs through the ErrorHandler interface, which requires a separate block of code. WebClient streamlines this with more fluent handling.
Örnek
Şöyle yaparız
WebClient webClient = WebClient.create();
webClient.get()
    .uri("http://example.com/some-error-endpoint")
    .retrieve()
    .onStatus(HttpStatus::isError, response -> {
        // Handle error status codes
        return Mono.error(new CustomException("Custom error occurred."));
    })
    .bodyToMono(String.class);
Açıklaması şöyle
The onStatus() method allows for handling specific HTTP statuses directly within the chain of operations, providing a more readable and maintainable approach.
POST
Örnek
Şöyle yaparız
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> request = new HttpEntity<>("{\"key\":\"value\"}", headers);
ResponseEntity<String> response = restTemplate
  .postForEntity("http://example.com",  request, String.class);

WebClient webClient = WebClient.create();
Mono<String> response = webClient.post()
    .uri("http://example.com")
    .contentType(MediaType.APPLICATION_JSON)
    .bodyValue("{\"key\":\"value\"}")
    .retrieve()
    .bodyToMono(String.class);
Asynchronous Processing




31 Temmuz 2021 Cumartesi

SpringWebFlux WebClient Mono Dönüşümü

Giriş
WebClient cevabını Mono'ya dönüştürmek için yöntemler şöyle

1. bodyToMono
Örnek
Şöyle yaparız
WebClient webClient = WebClient.create();
Mono<String> responseOne = webClient.get()
    .uri("http://example.com/endpointOne")
    .retrieve()
    .bodyToMono(String.class);

Mono<String> responseTwo = webClient.get()
    .uri("http://example.com/endpointTwo")
    .retrieve()
    .bodyToMono(String.class);

// Use Mono.zip to execute requests concurrently
Mono.zip(responseOne, responseTwo).subscribe(results -> {
    System.out.println("Result 1: " + results.getT1());
    System.out.println("Result 2: " + results.getT2());
});

2. exchangeToMono Yöntemi
Örnek
Şöyle yaparız
WebClient webClient = WebClient.create();
Mono<String> getHttpNonBlocking(String url) {
    return webClient
            .get()
            .uri(url)
            .exchangeToMono(cr -> cr.bodyToMono(String.class));
}
3. exchange + flatmap Yöntemi
Örnek
Elimizde şöyle bir kod olsun. Bu kod hem Mono hem de Flux dönebiliyor. Hem get() hem de put() işlemi için exchange() çağrısı yapıyor. Kod bir  spring bean. İskeleti şöyle
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;

@Component
public class WebClientHelper {

  private WebClient webClient;

  public WebClientHelper() {
    webClient = WebClient.create();
  }
}
Get ve Post için Mono dönen metodlar şöyle
public <T> Mono<T> performGetToMono(URI uri, MultiValueMap<String, String> params,
Class<? extends T> clazzResponse){
    return webClient.get()
        .uri(uriBuilder -> uriBuilder.scheme(uri.getScheme()).host(uri.getHost())
            .port(uri.getPort()).path(uri.getPath()).queryParams(params).build()
        )
        .exchange()
        .flatMap(clientResponse -> clientResponse.bodyToMono(clazzResponse));
}
public <T> Mono<T> performPostToMono(URI uri, Object requestBody,
Class<? extends T> clazzResponse){
    return webClient.post()
        .uri(uriBuilder -> uriBuilder.scheme(uri.getScheme()).host(uri.getHost())
            .port(uri.getPort()).path(uri.getPath()).build()
        )
        .body(BodyInserters.fromValue(requestBody))
        .exchange()
        .flatMap(clientResponse -> clientResponse.bodyToMono(clazzResponse));
}
Put ve Delete için Mono dönen metodlar şöyle
public <T> Mono<T> performPutToMono(URI uri, Object requestBody,
Class<? extends T> clazzResponse){
    return webClient.put()
        .uri(uriBuilder -> uriBuilder.scheme(uri.getScheme()).host(uri.getHost())
            .port(uri.getPort()).path(uri.getPath()).build()
        )
        .body(BodyInserters.fromValue(requestBody))
        .exchange()
        .flatMap(clientResponse -> clientResponse.bodyToMono(clazzResponse));
}
public <T> Mono<T> performDeleteToMono(URI uri, MultiValueMap<String, String> params,
Class<? extends T> clazzResponse){
    return webClient.delete()
        .uri(uriBuilder -> uriBuilder.scheme(uri.getScheme()).host(uri.getHost())
            .port(uri.getPort()).path(uri.getPath()).queryParams(params).build()
        )
        .exchange()
        .flatMap(clientResponse -> clientResponse.bodyToMono(clazzResponse));
}
Bu kodu kullanmak için şöyle yaparız
@RestController
@RequestMapping("/employeeClient")
public class EmployeeClientController {

  @Value("${employee.server.host}")
  private String employeeHost;

  @Autowired
  private WebClientHelper webClientHelper;

  @GetMapping("/{employeeId}")
  public Mono<EmployeeModel> getEmployeeById(@PathVariable("employeeId")
String employeeId){
    String url = ApiPaths.getEmployeePath(employeeHost) + "/" + employeeId;
    return webClientHelper.performGetToMono(URI.create(url), null, EmployeeModel.class);
  }
 
  @PostMapping
  public Mono<EmployeeModel> saveEmployee(@RequestBody EmployeeModel employeeModel){
    return webClientHelper.performPostToMono(URI.create(ApiPaths.getEmployeePath(
employeeHost)), employeeModel,
        EmployeeModel.class);
  }
...
}
Update ve Delete için şöyle yaparız
@PutMapping
public Mono<EmployeeModel> updateEmployee(@RequestBody EmployeeModel employeeModel){
  return webClientHelper
    .performPutToMono(URI.create(ApiPaths.getEmployeePath(employeeHost)), employeeModel,
      EmployeeModel.class);
  }
@DeleteMapping("/{id}")
public Mono<EmployeeModel> deleteEmployee(@PathVariable("id") Long employeeId){
  String url = ApiPaths.getEmployeePath(employeeHost) + "/" + employeeId;
  return webClientHelper.performDeleteToMono(URI.create(url),null, EmployeeModel.class);
}

2 Ocak 2020 Perşembe

SpringWebFlux WebClient Arayüzü

Giriş
Bu sınıf spring webflux projesine ait. Açıklaması şöyle.
Behind the scenes, WebClient calls an HTTP client. Reactor Netty is the default and reactive HttpClient of Jetty is also supported. Moreover, it's possible to plug other implementations of HTTP client by setting up a ClientConnector for WebClient.
Singleton
Açıklaması şöyle
Unlike RestTemplate, which was often instantiated per request or service, WebClient is designed to be used as a singleton. This means you should create a single instance of WebClient and reuse it across your application. This approach ensures efficient resource utilization and avoids the overhead of repeatedly creating and destroying WebClient instances.
Örnek
Şöyle yaparız
@Bean public WebClient.Builder webClientBuilder() { return WebClient.builder(); }
Kullanım
WebClient nesneyi yaratmak için iki tane yöntem var
1. WebClient.create() metodu ile bir WebClient nesnesi oluşturulur
2. WebClient.Builder.build() ile bir WebClient nesnesi oluşturulur

Daha sonra elimizdeki WebClient nesnesinin
delete()
get()
head()
options()
metodları kullanılarak bir WebClient.RequestHeadersUriSpec<?> nesnesi elde edilir.

veya
patch()
post()
put()
metodları kullanılarak WebClient.RequestBodyUriSpec nesnesi elde edilir.

WebClient Flux Dönüşümü yazısına bakabilirsiniz
WebClient Mono Dönüşümü yazısına bakabilirsiniz

Örnek
Şöyle yaparız
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

public ResponseEntity<List<CustomerClientResponse>> getCustomerListWithTotalPagesHeader(Integer page, Integer size) {
  return WebClient.create()
    .get()
    .uri(builder -> builder.path(...)
                    .queryParam("page", page)
                    .queryParam("size", size).build())
    .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
    .retrieve()
    .toEntity(new ParameterizedTypeReference<List<CustomerClientResponse>>() {})
    .block();
}
create metodu
Netty kullanan bir WebClient nesnesi döndürür.

Örnek
Şöyle yaparız.
@GetMapping(path = "/streaming", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@ResponseBody
public Flux<Something> streamSomething() {
  return WebClient.create()
    .get().uri("http://example.org/resource")
    .retrieve().bodyToFlux(Something.class)
    .delaySubscription(Duration.ofSeconds(5))
    .repeat();
}
create metodu - String
Netty kullanan bir WebClient nesnesi döndürür.

Örnek
Şöyle yaparız
WebClient client = WebClient.create("https://example.com");
get metodu
WebClient.RequestHeadersUriSpec nesnesi döner.

post metodu
Şöyle yaparız.
WebClient webClient = WebClient.builder().baseUrl(baseUrl).build();

webClient.post().uri(uri)
  .contentType(MediaType.APPLICATION_JSON_UTF8)
  .accept(MediaType.APPLICATION_JSON_UTF8)
  .header(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils
  .encodeToString((plainCreds)
  .getBytes(Charset.defaultCharset())))
  .body(BodyInserters.fromObject(body)).retrieve()
  .bodyToFlux(EmployeeInfo.class)
  .doOnError(throwable -> {
    ...
  }).subscribe(new Consumer<EmployeeInfo>() {
    @Override
    public void accept(EmployeeInfo employeeInfo) {
      ...
    }
}); 
Örnek
Şöyle yaparız
@RestController
@RequestMapping("/api")
public class WebClientController {

  @Autowired
  private WebClient webClient;

  @GetMapping("/posts/{id}")
  public Mono <Post> getPost(@PathVariable String id) {
    return webClient.get()
      .uri("/question/{id}", id)
      .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
      .retrieve()
      .bodyToMono(Post.class);
  }

  @GetMapping("/posts")
  public Mono<String> getPosts() {
    return webClient.get()
      .uri("/question/")
      .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
      .retrieve()
      .bodyToMono(String.class);
  }

  @PostMapping("/posts")
  public Mono <String> createPost(final Post post) {
    return webClient.post()
      .uri("/question/")
      .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
      .body(Mono.just(post), Post.class)
      .retrieve()
      .bodyToMono(String.class);
    }
}
timeout metodu
Örnek
Şöyle yaparız
return webClient()
  .get()
  .uri("https://www.google.com")
  .exchangeToMono(
    response -> {
      if (response.statusCode().equals(HttpStatus.OK)) {
        return Mono.just("OK");
      }
      return Mono.just("OK");
    })
  .timeout(Duration.ofMillis(500)); //Timeout specified here