"Welcome To Ashok IT" "Spring Boot & Microservices" Topic : RestClient Development Date : 18/06/2025 (Session - 69) _____________________________________________________________________________________________________________________________ Rest Client =========== * So far we developed the Rest API's and also how to generate documentation for Rest API's and also tested the Rest API's by using POSTMAN Tool and Swagger Documentation. * RestClient is a Java Program which is used to consume services from Rest API (or) Rest Client is used to access the Rest API's. * For Business-to-Business we will develop a program to access Rest API. * The Program which is accessing Rest API can be called as "Rest Client". * Inorder to develop Rest Client, We need Rest API Documentation. * Rest API documentation will be provided through Swagger and with out knowing the API Details Of Rest API we can't develop the RestClient Application. * We can develop the RestClient in Spring by using three techniques 1) HttpClient 2) RestTemplate 3) WebClient >>>>>>>>>>>> Introduced in Spring 5.X. 4) FeignClient >>>>>>>>>>>> Spring Cloud. * RestTemplate is used to develop the Rest Clients in synchronous manner that means after making Rest Call we have to wait untill we received response from Rest API then only our execution will continue. RestTemplate is an predefined Class which does not comes through Auto Configuration process... It must be created object for this class either by using "new" keyword (or) @Bean method Example ======= 1) RestTemplate rt = new RestTemplate(); (or) 2) @Bean public RestTemplate getRestTemplateObj(){ return new RestTemplate(); } RestTemplate class contains lot of utility methods such as getForEntity(),getForObject(),postForEntity(),exchange() etc., NOTE: ===== * JdbcTemplate,RestTemplate,NamedParameterJdbcTemplate,JndiTemplate etc., classes are given based template method design pattern which says that the template class takes care of common logics and programmer should take care of Specific Logics. * WebClient is modern API which is used to develop Rest Client and by using webclient we can develop both synchronous & Unsynchronous clients and we can say that Webclient is replacement of RestTemplate. * Feign Client is part of Spring Cloud Library. Steps for Developing Rest Client Program ======================================== 1) Create new Spring boot project with below dependencies 1) Spring Web 2) Spring Dev Tools 2) Develop the ApplicationConfig to mark the RestTemplate as Spring Bean ApplicationConfig.java ======================= package com.ashokit.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class ApplicationConfig { //Mark the RestTemplate class as spring bean @Bean public RestTemplate getRestTemplateObject() { return new RestTemplate(); } } 3) Develop the RestClient Program in Main Class Application.java ================ package com.ashokit; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; @SpringBootApplication public class Application implements ApplicationRunner { @Autowired private RestTemplate restTemplate; public static void main(String[] args) { SpringApplication.run(Application.class, args); } @SuppressWarnings("deprecation") @Override public void run(ApplicationArguments args) throws Exception { //API Details :::: http://localhost:8732/customers/wishes // :::: GET Request API with out PathVariable // :::: String As Response String endPointURL = "http://localhost:8732/customers/wishes"; ResponseEntity forEntity = restTemplate.getForEntity(endPointURL, String.class); int statusCodeValue = forEntity.getStatusCodeValue(); if(statusCodeValue == 200) { System.out.println("API Response ::::" + forEntity.getBody()); //Getting Response Body } //API Details :::: http://localhost:8732/customers/wishes/{username} // :::: Path Variable name :::: username // :::: GET Request API With PathVariables // :::: String as Response endPointURL = "http://localhost:8732/customers/wishes/{username}"; ResponseEntity forEntity2 = restTemplate.getForEntity(endPointURL, String.class, Map.of("username","Mahesh")); HttpStatusCode statusCode = forEntity2.getStatusCode(); if(statusCode.is2xxSuccessful()) { String responseBody = forEntity2.getBody(); System.out.println("API Response::::::" + responseBody); } //working with getForObject() String responseBody = restTemplate.getForObject(endPointURL, String.class, Map.of("username","Ashok")); System.out.println("API Response::::" + responseBody); } } OUTPUT ====== API Response ::::Welcome To Customer Controller... API Response::::::Welcome To Customer Controller Mahesh API Response::::Welcome To Customer Controller Ashok NOTE: ===== * Make sure Producer Application should be run and UP and also verify those API's are working or not by testing through postman (or) Swagger. IIQ) Differences between getForEntity() Vs getForObject() ? -> getForEntity() return type is ResponseEntity which contains more details of response object(Response status code,Response Body,Response Headers etc.,) -> getForObject() return type is T(Typed Parameter) simply will returns the Response Body. Application.java ================ package com.ashokit; import java.time.LocalDate; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatusCode; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import com.ashokit.dto.PersonDTO; import com.fasterxml.jackson.databind.ObjectMapper; @SpringBootApplication public class Application implements ApplicationRunner { @Autowired private RestTemplate restTemplate; public static void main(String[] args) { SpringApplication.run(Application.class, args); } @SuppressWarnings("deprecation") @Override public void run(ApplicationArguments args) throws Exception { //API Details :::: http://localhost:8732/customers/wishes // :::: GET Request API with out PathVariable // :::: String As Response String endPointURL = "http://localhost:8732/customers/wishes"; ResponseEntity forEntity = restTemplate.getForEntity(endPointURL, String.class); int statusCodeValue = forEntity.getStatusCodeValue(); if(statusCodeValue == 200) { System.out.println("API Response ::::" + forEntity.getBody()); //Getting Response Body } //API Details :::: http://localhost:8732/customers/wishes/{username} // :::: Path Variable name :::: username // :::: GET Request API With PathVariables // :::: String as Response endPointURL = "http://localhost:8732/customers/wishes/{username}"; ResponseEntity forEntity2 = restTemplate.getForEntity(endPointURL, String.class, Map.of("username","Mahesh")); HttpStatusCode statusCode = forEntity2.getStatusCode(); if(statusCode.is2xxSuccessful()) { String responseBody = forEntity2.getBody(); System.out.println("API Response::::::" + responseBody); } //working with getForObject() String responseBody = restTemplate.getForObject(endPointURL, String.class, Map.of("username","Ashok")); System.out.println("API Response::::" + responseBody); //working with exchange() endPointURL = "http://localhost:8732/customers/wishes"; ResponseEntity exchangeMessage = restTemplate.exchange(endPointURL, HttpMethod.GET, null, String.class); if(exchangeMessage.getStatusCodeValue() == 200) { String responseMessage = exchangeMessage.getBody(); System.out.println("API Response:::::" + responseMessage); } //API Details ::: http://localhost:8732/persons/ PersonDTO dto = new PersonDTO(); dto.setName("Test-1"); dto.setEmailId("test-1@ashokit.com"); dto.setContactNo("1232323333"); dto.setLocation("Hyderabad"); //dto.setCreatedDate(LocalDate.now()); //converting the Java Object into JSON ObjectMapper objectMapper = new ObjectMapper(); String jsonString = objectMapper.writeValueAsString(dto); System.out.println("JSON String::::" + jsonString); //Prepare Headers HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); //Preparing the HttpRequest using HttpEntity object with headers HttpEntity request = new HttpEntity<>(jsonString,headers); ResponseEntity postForEntity = restTemplate.postForEntity("http://localhost:8732/persons/", request, String.class); if(postForEntity.getStatusCodeValue() == 201) { String postResponse = postForEntity.getBody(); System.out.println("API Response:::::" + postResponse); } } } OUTPUT ====== API Response ::::Welcome To Customer Controller... API Response::::::Welcome To Customer Controller Mahesh API Response::::Welcome To Customer Controller Ashok API Response:::::Welcome To Customer Controller... JSON String::::{"id":null,"name":"Test-1","location":"Hyderabad","contactNo":"1232323333","emailId":"test-1@ashokit.com","createdDate":null} API Response:::::Person Registered Successfully With Person ID Has :::::13 * RestTemplate Class will support the "Synchronous Calls" and also called as "Blocking Call" Nature. RestTemplate Utility Methods ============================ 1) getForEntity() 2) getForObject() 3) postForEntity() 4) postForObject() 5) put() 6) delete() 7) patchForObject() WebClient ========= * Developing RestClient application using "WebClient" and this webclient given from Spring 5.x Version onwards. * Webclient can support for both synchronous & Asynchronous Communications. * Working with Webclient is nothing but Spring Reactive Programming. * Spring Reactive Programming is one kind of programming style which can be executed Java logic based on events. * Inorder to support Reactive Programming in Spring Boot we need to use the following starter i.e., "Springboot-starter-webflux" (Reactive Web) in our pom.xml file. * In Reactive Programming we have two important keywords 1) mono >>>>>> Mono object always representing Single Response from Rest API. 2) flux >>>>>> Flux object always representing the Continous Response from Rest API. Steps for Developing WebClient Application =========================================== 1) Create Spring Boot Application with below starters - Spring Web - Spring Reactive Web 2) Develop the Client Application for below code Application.java ================ package com.ashokit; import java.net.URI; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.client.WebClient; import com.ashokit.dto.PersonDTO; import com.fasterxml.jackson.databind.ObjectMapper; @SpringBootApplication public class Application implements ApplicationRunner{ public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override public void run(ApplicationArguments args) throws Exception { //Creating WebClient object WebClient webClient = WebClient.create(); //Defining the endpoint URL String endPointURL = "http://localhost:8899/api/login/"; String responseMessage = webClient.get() //This is for testing Get Request API .uri(new URI(endPointURL)) //This for defining the REST API URL .retrieve() //This for retrieving API Response Body .bodyToMono(String.class)//Defining Response Type .block();//It will block thread until we got response from Rest API System.out.println("API Response::::::" +responseMessage); System.out.println("================================================================="); //Callback methods webClient.get() .uri(new URI(endPointURL)) .retrieve() .bodyToMono(String.class) .subscribe(Application :: responseHandling); //API Details ::: http://localhost:8899/api/persons/ PersonDTO dto = new PersonDTO(); dto.setName("Test-2"); dto.setEmailId("test-2@ashokit.com"); dto.setContactNo("1232323333"); dto.setLocation("Hyderabad"); //converting the Java Object into JSON ObjectMapper objectMapper = new ObjectMapper(); String jsonString = objectMapper.writeValueAsString(dto); System.out.println("JSON String::::" + jsonString); //WebClient using post API String postResponse = webClient.post() .uri(new URI("http://localhost:8732/persons/")) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonString) .retrieve() .bodyToMono(String.class) .block(); System.out.println("Post Response:::::"+ postResponse); } public static void responseHandling(String message) { System.out.println("API Response::::::" + message); } } OUTPUT ====== API Response::::::Welcome To Customer Controller... =================================================== API Response::::::Welcome To Customer Controller... JSON String::::{"id":null,"name":"Test-2","location":"Hyderabad","contactNo":"1232323333","emailId":"test- 2@ashokit.com","createdDate":null} Post Response:::::Person Registered Successfully With Person ID Has :::::15 JUnit ====== * Unit testing framework which helps to test piece of code written project. * Developer level testing framework. JUnit 5 ======= JUnit 5 is a popular framework for writing and running tests in Java. It is the next generation of JUnit, built to take advantage of Java 8+ features, and consists of three main modules: JUnit Platform =============== * Acts as a foundation for launching testing frameworks on the JVM. * Provides a TestEngine API for developing custom testing frameworks. * Enables running tests from JUnit 5 and other test engines like Spock or Cucumber. JUnit Jupiter ============= * The main module for writing tests in JUnit 5. * Introduces new annotations and programming models. * Provides better support for parameterized tests, extensions, and more flexible lifecycle hooks. JUnit Vintage ============= * Provides backward compatibility for running JUnit 3 and JUnit 4 tests on the JUnit Platform. * Useful when migrating existing projects to JUnit 5. Annotations ============ JUnit 5 introduces new annotations that simplify testing: 1.@Test: Marks a method as a test method. 2.@BeforeEach and @AfterEach: Run before/after each test method. 3.@BeforeAll and @AfterAll: Run once before/after all test methods (must be static). 4.@DisplayName: Customizes test method names for better readability. 5.@Disabled: Disables a test or class. 6.@Nested: Creates nested test classes for better organization. 7.@Tag: Groups tests to control which are executed. Assertions ========== * assertEquals(expected, actual), assertTrue(condition), assertNotNull(object), etc. * Support for grouped and dependent assertions using assertAll. Parameterized Tests =================== * Annotations like @ParameterizedTest, @ValueSource, @CsvSource, and @MethodSource allow you to run a test with multiple inputs. Example ======= import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.*; class CalculatorTest { private Calculator calculator; @BeforeEach void setUp() { calculator = new Calculator(); } @Test @DisplayName("Addition works correctly") void testAddition() { assertEquals(5, calculator.add(2, 3), "2 + 3 should equal 5"); } @Test @Disabled("Not implemented yet") void testSubtraction() { // Test case to be implemented } @ParameterizedTest @ValueSource(ints = {2, 3, 5, 7, 11}) void testIsPrime(int number) { assertTrue(calculator.isPrime(number), number + " should be prime"); } @AfterEach void tearDown() { calculator = null; } } Junit Workshop ============== https://www.youtube.com/watch?v=3FutI2_Tix8 https://www.youtube.com/watch?v=UhByIkYqHcg (01:25- Mockito) https://www.youtube.com/watch?v=xL4OlQ_W3Ek https://github.com/maheshashokit/JUnit_Workshop_Apps