حتما تا حالا شده بخواید با API دیگه ای تو برنامتون ارتباط برقرار کنید و دنبال بهترین روش یا بهترین Library موجود بودید. اگه از Spring MVC استفاده میکنید با اولین جستجو به RestTemplate میرسید. ولی میبینید که deprecate شده!
بعد از معرفی Spring Webflux و رویکرد Reactive Programming دیگه RestTemplate به دلیل synchronous و بلوکه کردن Thread پاسخگو این بخش نبود. همین باعث شد که WebClient با رویکرد fluent API توسعه پیدا کنه و بصورت non-blocking امکان ارتباط با API های دیگه رو بده. همچنین اگه از Spring MVC هم استفاده میکنید، میشه با اضافه کردن Spring Webflux به dependency ها و فراخونی تابع block() در انتها، بصورت synchronous از این کلاینت هم استفاده کرد. ولی خب اینکه یک dependency جدا به برنامه تون اضافه شه و با مفاهیم Reactive Programming مواجه بشید اون هم تو Spring MVC شاید خیلی خوشایند نباشه.
تو ورژن 6.1 Spring Framework کلاینت جدیدی با نام RestClient به عنوان synchronous HTTP client معرفی شد. RestClient هم مثل WebClient از fluent API استفاده میکنه و با فراخونی بصورت method chaining کار رو خیلی ساده میکنه و خوانایی کد رو بالا میبره. RestClient از HTTP interfaces هم پشتیبانی میکنه و کار رو به شدت راحت تر و خوانا تر کرده.
بریم یه نمونه ساده استفاده از RestClient رو ببینیم.
اول با استفاده از Spring Boot یک api ساده برای تست ایجاد میکنیم. این api شامل متودهای GET,POST,PUT,UPDATE,DELETE بر روی موجودیت Customer است که بصورت زیر تعریف شده:
public class Customer { private Integer id; private String firstName; private String lastName; private List<Address> addressList; }
کلاس CustomerController هم بصورت زیر تعریف میکنیم:
@RestController @RequestMapping("/customers") public class CustomerRestController { private final CustomerService customerService; public CustomerRestController(CustomerService customerService) { this.customerService = customerService; } @GetMapping() public List<Customer> getAllCustomers() { return this.customerService.getAllCustomers(); } @GetMapping("{id}") public Customer getCustomerById(@PathVariable("id") int id) { return this.customerService.getCustomerById(id); } @PostMapping() public void addNewCustomer(@RequestBody Customer customer) { this.customerService.createCustomer(customer); } @PutMapping public void updateCustomer(@RequestBody Customer customer) { this.customerService.updateCustomer(customer); } @DeleteMapping("{id}") public void deleteCustomer(@PathVariable("id") int id) { this.customerService.deleteCustomer(id); } }
برای ایجاد احراز هویت از Spring Security استفاده میکنیم و بصورت ساده با استفاده http basic تنظیمات رو اعمال میکنیم:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) { UserDetails user = User.withUsername("user") .password(passwordEncoder.encode("user")) .roles("user") .build(); return new InMemoryUserDetailsManager(user); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { return httpSecurity .csrf(csrf -> { csrf.disable(); }) .cors(cors -> cors.disable()) .authorizeHttpRequests(auth -> { auth.requestMatchers("/sample/**").permitAll(); auth.anyRequest().authenticated(); }) .httpBasic(Customizer.withDefaults()) .build(); } }
کد کامل رو میتونید اینجا ببینید.
یک سرویس جدید برای ارتباط با API میسازیم. برای ارتباط با API از RestClient استفاده میکنیم که با اضافه کردن Spring-Web-MVC به پروژه در دسترس قرار میگیره. تو مرحله قبل برای secure کردن endpoint ها از یورز و پسورد user استفاده کردیم و پورت هم روی 8081 گذاشتیم. برای راحتی و externalize کردن مقادیر میایم اون ها رو داخل فایل application.properties قرار میدیم و بعد در کدمون استفاده میکنیم:
server.port=8083 application.api.url=http://localhost:8081/api application.api.username=user application.api.password=user
برای ساخت Bean از RestClient راه های مختلفی وجود داره که یکی از اون ها استفاده از builder هست. یک کلاس بنام RestClientConfig میسازیم و مقادیر رو از فایل application.properties میخونیم. همونطور که گفتیم RestClient از fluent api پشتیبانی میکنه و میتونیم توابع رو بصورت زنجیره ای فراخونی کنیم که خوانایی کد رو به شدت بالا میبره:
@Configuration public class RestClientConfig { @Value("${application.api.url}") private String url; @Value("${application.api.username}") private String username; @Value("${application.api.password}") private String password; @Bean public RestClient restClient() { String auth = "Basic " + Base64 .getEncoder() .encodeToString((username + ":" + password).getBytes()); return RestClient.builder() .baseUrl(url) .defaultHeader( HttpHeaders.AUTHORIZATION, auth ).build(); } }
تا اینجا RestClient ما تنظیماتش انجام شده و برای ارتباط با api آمادست.
با استفاده GET method میتونیم دیتا رو از api بگیریم و به راحتی به entity مورد نظرمون تبدیلش کنیم. برای گرفتن لیستی از Customer ها بصورت زیر عمل میکنیم:
List<Customer> customers = restClient.get() .uri("/customers") .accept(MediaType.APPLICATION_JSON) .retrieve() .body(new ParameterizedTypeReference<List<Customer>>() {});
میتونیم تو بخش uri پارامتر هم جایگذاری کنیم و همچنین برای هندل کردن خطاها هم میتونیم از onStatus استفاده کنیم. برای مثال برای دریافت یک Customer از کد زیر رو مینویسیم:
int id = 1; Customer customer = restClient.get() .uri("/customers/{id}", id) .accept(MediaType.APPLICATION_JSON) .retrieve() .onStatus(status -> status.value() == 404, (request, response) -> logger.info("404 not found")) .body(Customer.class);
برای ارسال اطلاعات و درخواست ایجاد یک Customer جدید از post استفاده میکنیم:
Customer customer = new Customer(); customer.setFirstName("new customer"); customer.setLastName("new customer"); ResponseEntity responseEntity = restClient.post() .uri("/customers") .contentType(MediaType.APPLICATION_JSON) .body(customer) .retrieve() .toBodilessEntity(); logger.info("response code=" + responseEntity.getStatusCode());
با استفاده از put میتونیم درخواست آپدیت یک entity رو ارسال کنیم و با استفاده از delete هم میتونیم درخواست حذف یک entity رو ایجاد کنیم.
کد کامل رو میتونید اینجا ببینید.
تو این مقاله سعی کردیم یک معرفی خیلی کوتاه از RestClient داشته باشیم که به عنوان جایگزینی برای RestTemplate معرفی شده و با استفاده از fluent API کار رو خیلی ساده و خوانا تر کرده.
ممنون که مقاله رو خوندید. امیدوارم مفید بوده باشه.