SpringBoot ile RestTemplate/FeignClient Kullanımı
Microservice mimarisinin hayatımıza girmesiyle birlikte teknolojisi ve ölçeği ne olursa olsun API’ler arasında etkili iletişim kurma ve third party API’leri sistemlerimize entegre etme ihtiyacı duymaktayız.
Java’da Rest API çağırımları oluşturmanın bir kaç yolu vardır ve bunlardan iki tanesi de yazımda değinecek olduğum RestTemplate ve FeignClient kullanımlarıdır.
RestTemplate
RestTemplate, client tarafında senkronize HTTP isteklerini yürütmek için kullanılan spring-boot-starter-web paketinde yer alan bir sınıftır.
RESTful hizmetlerinin çağrılmasını kolaylaştıran metotların her birini sağlar.
RestTemplate kullanımını, örnek bir uygulama üzerinde inceleyelim.
İki adet Spring Boot uygulamamız olduğunu düşünelim.
- SubscriptionService : Subscription uygulaması verilen müşteri numarasına göre ilgili müşterinin abonelik kayıtlarının detayını dönen bir servise sahiptir. http://localhost:8080/cashmanagement/subscription/details
- CashflowService : Cashflow uygulaması içindeki servis ise subscription içinde yazılmış olan servisi kullanarak ilgili müşterinin abonelik kayıtlarına erişmek istemektedir. http://localhost:8081/cashmanagement/cashflow/subscription/details
Subscription uygulamasındaki controller ve service class’ları aşağıdaki gibidir.
package com.cashmanagement.subscription.controller;
import com.cashmanagement.subscription.model.SubscriptionDetailsRequest;
import com.cashmanagement.subscription.model.SubscriptionDetailsResponse;
import com.cashmanagement.subscription.service.SubscriptionService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/cashmanagement/subscription")
public class SubscriptionController {
@PostMapping("/details")
public SubscriptionDetailsResponse getSubscriptionDetails(@RequestBody SubscriptionDetailsRequest request) {
return SubscriptionService.getSubscriptionDetails(request);
}
}
package com.cashmanagement.subscription.service;
import com.cashmanagement.subscription.model.SubscriptionDetailsRequest;
import com.cashmanagement.subscription.model.SubscriptionDetailsResponse;
public class SubscriptionService {
public static SubscriptionDetailsResponse getSubscriptionDetails(SubscriptionDetailsRequest request) {
SubscriptionDetailsResponse subscriptionDetailsResponse = new SubscriptionDetailsResponse();
if ("12345".equalsIgnoreCase(request.getCustomerNumber())){
subscriptionDetailsResponse.setMerchantName("Netflix");
subscriptionDetailsResponse.setTransactionDate("12-12-2023");
subscriptionDetailsResponse.setTransactionAmount("350.0");
} else if ("67890".equalsIgnoreCase(request.getCustomerNumber())){
subscriptionDetailsResponse.setMerchantName("Amazon");
subscriptionDetailsResponse.setTransactionDate("11-12-2023");
subscriptionDetailsResponse.setTransactionAmount("150.0");
}
return subscriptionDetailsResponse;
}
}
Cashflow uygulaması içinde subscription servisini çağırabilmek için öncelikle ilgili servisin response’una ait class yaratılır.
package com.cashmanagement.cashflow.model.subscription;
public class SubscriptionDetailsResponse {
private String merchantName;
private String transactionDate;
private String transactionAmount;
//getters and setters
}
RestTemplate exchange metodunu kullanan ilgili callRestService metodu oluşturulur.
package com.cashmanagement.cashflow.util;
import org.springframework.http.*;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;
public class RestUtil {
@SuppressWarnings("unchecked")
public static <V, T> V callRestService(T inputData, Class<V> outputClass, String restUrl) {
ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());
RestTemplate restTemplate = new RestTemplate(factory);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.set("Content-Type", "application/json");
HttpEntity<T> entity = (HttpEntity<T>) new HttpEntity<>(inputData, headers);
ResponseEntity<V> result = restTemplate.exchange(restUrl, HttpMethod.POST, entity, outputClass);
return result.getBody();
}
}
Cashflow uygulamasındaki controller ve service class’ları da aşağıdaki gibidir.
package com.cashmanagement.cashflow.controller;
import com.cashmanagement.cashflow.model.subscription.SubscriptionDetailsRequest;
import com.cashmanagement.cashflow.model.subscription.SubscriptionDetailsResponse;
import com.cashmanagement.cashflow.service.CashflowService;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/cashmanagement/cashflow")
public class CashflowController {
@PostMapping("/subscription/details")
public SubscriptionDetailsResponse getSubscriptionDetails(@RequestBody SubscriptionDetailsRequest request) {
return CashflowService.getSubscriptionDetails(request);
}
}
package com.cashmanagement.cashflow.service;
import com.cashmanagement.cashflow.model.subscription.SubscriptionDetailsRequest;
import com.cashmanagement.cashflow.model.subscription.SubscriptionDetailsResponse;
import com.cashmanagement.cashflow.util.RestUtil;
public class CashflowService {
public static SubscriptionDetailsResponse getSubscriptionDetails(SubscriptionDetailsRequest request) {
SubscriptionDetailsResponse detailsResponse;
String url = "http://localhost:8080/cashmanagement/subscription/details";
detailsResponse = RestUtil.callRestService(request,SubscriptionDetailsResponse.class,url);
return detailsResponse;
}
}
FeignClient
FeignClient, Rest API çağırımlarını kolaylaştıran başka bir REST client kullanımıdır. Feign’i kullanırken sadece interface tanımlamamız ve onlara ilgili annotation’ları eklememiz yeterlidir.
FeignClient kullanımının avantajları nelerdir?
- Kullanımının kolay olmasıyla beraber kodlama eforu en aza indirilerek daha anlaşılır ve temiz bir yapı elde edilir.
- FeignClient kullanımı ile somut sınıfa veya uygulamaya bağlı kalınmaz.
- Tanımlanan interface ile IP ve Port bilgileri tek bir yerden kontrol edilir.
- Hangi endpoint’lerin kullanıldığı interface üzerinden kolaylıkla takip edilebilir.
- Spring’in RestTemplate özelinde değişiklik yapması durumunda geriye dönük çalışma yapılmasına gerek kalmaz.
Yukarıda restTemplate kullanarak gerçekleştirdiğimiz Rest API çağırımını feignClient kullanarak tekrar düzenleyelim.
Cashflow uygulaması FeignClient üzerinden istek göndereceği için pom.xml dosyasına aşağıdaki bağımlılık eklenir.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.2</version>
</dependency>
Main metodumuzun olduğu CashflowApplication sınıfına @EnableFeignClients annotation’ı eklenir.
package com.cashmanagement.cashflow;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class CashflowApplication {
public static void main(String[] args) {
SpringApplication.run(CashflowApplication.class, args);
}
}
SubscriptionFeignClient adında bir interface oluşturulur.
package com.cashmanagement.cashflow.util;
import com.cashmanagement.cashflow.model.subscription.SubscriptionDetailsRequest;
import com.cashmanagement.cashflow.model.subscription.SubscriptionDetailsResponse;
import feign.Headers;
import feign.RequestLine;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
@FeignClient(value = "subscription-service", url = "http://localhost:8080/cashmanagement/subscription")
public interface SubscriptionFeignClient {
@RequestLine("POST")
@Headers({ "Content-Type: application/json", "Accept: application/json" })
@PostMapping("/details")
SubscriptionDetailsResponse getSubscriptionDetails(SubscriptionDetailsRequest request);
}
CasflowController class’ı içinde tanımladığımız interface inject edilir ve getSubscriptionDetails metodu üzerinden Subscription uygulamasındaki servise istek gönderilir.
package com.cashmanagement.cashflow.controller;
import com.cashmanagement.cashflow.model.subscription.SubscriptionDetailsRequest;
import com.cashmanagement.cashflow.model.subscription.SubscriptionDetailsResponse;
import com.cashmanagement.cashflow.util.SubscriptionFeignClient;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/cashmanagement/cashflow")
public class CashflowController {
private SubscriptionFeignClient feignClient;
public CashflowController(SubscriptionFeignClient feignClient) {
this.feignClient = feignClient;
}
@PostMapping("/subscription/details")
public SubscriptionDetailsResponse getSubscriptionDetails(@RequestBody SubscriptionDetailsRequest request) {
return feignClient.getSubscriptionDetails(request);
}
}
Postman Service Çağırımları
Özetle, Rest API çağırımlarını gerçekleştirebilmek için RestTemplate ve FeignClient kullanımlarını bir örnek üzerinden implement’e ederek karşılaştırdık .
Bir sonraki yazımızda görüşmek üzere…