Spring HTTP Client : RestTemplate vs WebClient

Merhabalar, uzun bir aradan sonra bloğumun tozunu almaya geldim 🙂 Bu yazıda RestTemplate ve Webclient’tan bahsedeceğim.

RestTemplate,  client tarafında senkronize HTTP isteklerini yürütmek için kullanılan spring-boot-starter-web paketinde yer alan sınıftır.       Spring ayrıca spring-boot-starter-webflux paketinde WebClient adlı bir sınıfa sahiptir.  Bunlar, ” bir API’ye nasıl client olunur ? ” ‘un yöntemlerindendir.

Yani external bir API üzerindeki HTTP methodlarını nasıl çağıracağımızı veya bunlardaki geri dönüş değerlerini nasıl alıp işleyeceğimize yardımcı olurlar. Biz bu yazı da ikisini de ayrı ayrı projelerde örnekleyeceğiz.  Hangisi ile yolunuza devam edersiniz sizin kararınız . Bu karar üzerinde önemli etkiye sahip olacağını düşündüğüm bir bilgilendirme yapacak olursam  şöyle ki, springin dökümantasyonunda olan bir notu paylaşmak istiyorum ,

NOTE: As of 5.0 this class is in maintenance mode, with only minor requests for changes and bugs to be accepted going forward. Please, consider using the org.springframework.web.reactive.client.WebClient which has a more modern API and supports sync, async, and streaming scenarios.

Rest-template (blocking client), thread-per-request modeline dayanan  Java Servlet API’sini kullanır. Bu,  client yanıtı alana kadar thread’in blocklanacağı anlamına gelir. Uygulamada çok sayıda istek atılıyor ise bununla orantılı olarak çok sayıda thread kullanılacak ve connection oluşacaktır.  Sonuç olarak, uygulama, thread havuzunu tüketecek veya tüm kullanılabilir belleği işgal edecek birçok thread oluşturacaktır . Sık sık CPU bağlamı (thread) geçişi nedeniyle performans düşüşü yaşanacaktır..

WebClient , Spring WebFlux kütüphanesinin bir parçasıdır.  WebClient, spring reactive framework tarafından asynchronous,non-blocking işlemleri destekleyen reactive bir HTTP client’dır. Reactive işlemlerin yanısıra senkron ve blocking istekleri de destekler.

RestTemplate her event (HTTP call) için thread kullanırken,   WebClient her event için “task”  create eder. Arka tarafta işin nasıl yürüdüğüne bakacak olursak, Reactive framework bu “tasks” sıraya (Data Stream) koyar ve bunları yalnızca uygun yanıt oluştuğunda (execute) yürütür. Yani bir işlem adımının yürütülebilmesi için başka işlemlerin sonucu beklenmek zorunda değildir. Çalışma zamanında, asenkron bir işlem yürüten kod satırı çalıştırıldıktan sonra, işlemin bitmesi beklenmeden diğer satırdaki işlemler yürütülebilir. Multithread işlemler yürütebilen sistemlerde, asenkron yürütülecek olan işlemler, farklı thread’ler tarafından da yapılabilir.

Önemli bir not ise WebClient block() metoduyla birlikte RestTemplate benzeri senkron işlemleri de desteklemektedir.

Neden Asenkron çalışma ?

Programlamada asenkron çalışma, uygulamaları daha duyarlı hale getirmek amacıyla kullanılır. Asenkron işlemler genellikle uzun zaman alan işlemlerdir. Bu nedenle ana uygulama bir görevi yürütürken,” kilitlenme” ve “donma” adındaki  yavaşlamaları kullanıcıya yansıtmadan, iyi bir kullanıcı deneyimi sunmayı sağlar. Asenkron işlemler dış kaynaktan bir veriyi almak olabileceği gibi localde uzun ve karmaşık hesaplama gerektiren işlemler de olabilir.

Sonuç olarak, Reactive yaklaşım, synchronous/blocking yöntemine kıyasla daha az thread ve sistem kaynağı kullanırken daha fazla mantık işleyebilir.

Önemli bir not daha şu ki , bir uygulamanın reactive olması için uçtan uca bütün işlemlerin reactive yapıya uygun olması gerekir, başka servislere atacağımız Rest isteklerin ve testlerde kullanılacak Http isteklerinin de reactive bir http client altyapısına sahip olması gerekir.

Haydi gelin bunların nasıl kullanıldıklarını canlı canlı görelim ..

Client’ı olacağımız API Github Rest API olacak , herkese açıktır API dökümantasyonuna adresten ulaşabilirsiniz.

RestTemplate ile başlayalım,

pom.xml dosyamıza aşağıdaki bağımlılığı eklemek yeterli olacaktır.

https://api.github.com/users istek attığımızda karşımıza github’daki kullanıcıların json yapıda listelendiğini göreceksiniz. Şimdi bu yapıyı karşılayabileceğimiz pojo sınıfımızı oluşturalım . Ben kullanıcının response da ki tüm bilgilerini değil de bazı bilgilerini görüntülemek istiyorum model,

Spring projemizin run edileceği sınıfta @Bean annotation’ını kullanarak RestTemplate sınıfından otomatik olarak bir instance oluşturmamızı sağlıyacak bir yöntem geliştirelim. Buradaki logic, spring boot uygulaması initialize olduktan sonra RestTemplate() methodunu çağıracak ve bu methoddan oluşan nesneyi götürüp Iaas conteiner içine koyacak buradan da biz diğer classlar içinde ne zaman @Autowire diyerek yada constructInjection kullanarak restTemplate() bunu kullanmak istersek bu instance’a bağlanıp kullanıyor olacağız.

Şimdi ise Service sınıfımızı oluşturalım ve biraz da burada konuşalım,

GITHUB_API isminde bir base uri tanımladık bunu da RestTemplate’in getForEntity methodunda kullandık. Peki bu method ne anlama geliyor,

getForEntity aldığı parametrelerle kendisine bir URI verilmesini ve bu uri’den dönen nesneyi serialize edebileceği class’ın verilmesini istiyor.  Biz de aşağıda istediğini yapmış olduk,

şuan ki aşamada basitçe bir api’ye RestTemplate ile client olmuş olduk gelin şimdi de controller yazarak verileri çekmek için istekte bulunalım,

postman kullanarak get request gerçekleştirdiğimde  RestTemplate kullanarak github api’nin bize sunduğu kullanıcıları almış olduk.

Şimdi ise aynı örneği WebClient kullanarak gerçekleştirelim.

WebClient Spring Web Flux’ın bir parçası olduğu için spring projemize  “spring-boot-starter-webflux” bağımlılığını eklemeliyiz.

Bu projede bir configuration sınıfı oluşturdum böylece bütün temel ayarları builder ile bir defa tanımlayabilir ve sonrasında build edilmiş instance’ı kullanabiliriz. Her seferinde yeniden ayarları düzenlememize gerek kalmadan uygulamamızı geliştirmeye devam edebiliriz.

WebClient get()post()put()patch()delete()options() veya head() yöntemleri destekler.

Diğer işlemlere geçmeden önce birkaç yapıya göz atmamız gerekiyor.

  • uri() ile birlikte path’i, path variable’ları ve request parametrelerini belirtebiliriz.
  • headers()ile birlikte isteği atarken header’ları gönderebiliriz.
  • cookies() ile birlikte Cookie’lerimizi tanımlayabiliriz.
  • retrieve() metodunu isteği gerçekleştirmek ve server’dan aldığımız response’u veya hataları okumak için kullanabilirz.
  • exchange()ile birlikte daha kontrollü bir response işleme yapısı kurabiliriz. exchangeToFlux()veya exchangeToMono() metotlarını kullanarak direkt Flux ya da Mono objelerine dönüşüm sağlayabiliriz.
  • retryWhen() ile birlikte retry mekanizması kurabiliriz.

Son olarak attığımız işleme gelen cevabıbodyToMono() ile Mono’ya ve bodyToFlux() ile Flux’a dönüştürme işlemleri gerçekleştirebiliriz.

Mono: 0 ya da 1 tane event içerebilen Publisher’lar için kullanılır.

Flux0..N tane event’ı içeren publisher’lar için kullanılır.

WebClient Bean’imizi oluşturduğumuza göre onu kullanarak hızlıca asenkron istek atabilen bir metot yazabiliriz.

Bir işlemi senkron gerçekleştirebilmek için response’da dönen objeyi .toEntity() metoduyla belirtebilir .block() metoduyla isteğin blocking ve senkron olmasını sağlayabiliriz.

Örneklediğimiz bu yapı ile RestTemplate’in yerine de kullanılabilir bir yapı elde etmiş oluyoruz.

Hataları kontrol edip, kendi custom exception’larımızı da oluşturabileceğimiz yöntemlerden birisi .onStatus() ile hata durumlarını handle etmektir. .onStatus() metodu ile birlikte client ya da server tarafından oluşan hataları handle edebiliriz.

Son olarak WebClient ile birlikte senkron, asenkron operasyonların yanında error handling gibi konulara da değinmiş olduk.

Sonuç

WebClient Http isteklerinizi reactive olarak atabilmenizi sağlayan ve RestTemplate’e alternatif olarak sunulan en önemli Spring WebFlux kütüphanelerinden biridir. Hatırlatmak gerekirse uygulamanızda WebClient kullanıyor olmanız uygulamanızın reactive olduğu anlamına gelmez. Yazının başında da bahsetttiğimiz gibi bir uygulamanın reactive olabilmesi için uçtan uca asenkron ve non-blocking operasyonları içerebilmesi gerekmektedir hatta bir veritabanı kullanıyorsanız veritabanınında reactive desteği bulunması gerekmektedir.

RestTemplate projesi için spring-boot-rest-template adlı github repomu inceleyebilirsiniz

WebClient örneklediğim proje için spring-boot-webclient-rest adlı Github repomu inceleyebilirsiniz.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir