Apart from three well known layers i.e. Presentation Layer, Service Layer and Data Layer, we may also have an Integration Layer. This layer generally works with the web services concept and connects two different applications to exchange data between them. One application refers to producer/provider, whereas other refers to consumers. However, we have already gone through the REST Producer API in another article where we had developed different operations to produce REST API. Now, we must have a question in mind 'How to write REST Consumer API using Spring Boot RestTemplate'. We had also discussed a bit about RestTemplate( The Spring REST Client).
In fact, RestTemplate provides us Consumer methods to consume services provided by producer applications. We can even have various non-java Consumer applications. However, our RestTemplate is written in Java only. Accordingly, let's start working on 'How to write REST Consumer API using Spring Boot RestTemplate'.
Table of Contents (Click on links below to navigate)
- 1 What will you learn from this article ?
- 2 What is Rest Template ?
- 3 What is difference between getForObject() and getForEntity() ?
- 4 What is difference between postForObject() and postForEntity() ?
- 5 What is exchange() method in RestTemplate used for ?
- 6 What is the format of data Consumer Application receives from Producer Application ?
- 7 What all parameters are expected to write consumer methods in RestTemplate ?
- 8 How to implement RestTemplate methods ?
- 8.1 Save Invoice
- 8.2 Get All Invoices
- 8.3 Get One Invoice
- 8.4 Update Invoice
- 8.5 Delete Invoice
- 9 Complete Code
- 10 How to test the application ?
- 11 How to convert ResponseEntity to Java object ?
- 11.1 Solution#1 : By using getForEntity() method and returning Array Of Objects
- 11.2 Solution#2 : By using exchange() method and returning List Of Objects
- 11.3 Solution#3 : By using exchange() method and returning Array Of Objects
- 12 Summary
What will you learn from this article ?
1) What is RestTemplate and what is it used for?
2) What is the difference between the various methods of RestTemplate?
3) When to use, which method of RestTemplate?
4) How is the exchange () method used in implementing Rest Consumer Web Services?
5) Also, Which format of data does the producer application provide and which format of data does the consumer application receive?
6) What are all parameters of RestTemplate method to develop the consumer application?
7) How to write a REST Consumer API using Spring Boot: RestTemplate?
8) Additionally, How to use slf4j Logger effectively while implementing RestTemplate?
9) Finally, How to test the developed application?
What is Rest Template ?
In a nutshell, RestTemplate is a predefined class in Spring Boot REST project. Moreover It helps in making HTTP calls to Producer application with all method types eg. GET, POST, PUT, DELETE etc. However Spring Boot framework doesn't auto configure this class. It also supports JSON/XML to Object and Object to JSON/XML auto-conversion. Moreover, it requires Endpoint details from a producer application like IP, PORT, Paths, Method Type, Input data format and Output data format etc. Additionally, RestTemplate provides the exchange() method to consume the web services for all HTTP methods. In fact, RestTemplate helps in making HTTP Rest Calls.
What is difference between getForObject() and getForEntity() ?
Having knowledge of getforentity vs getforobject is important for us as we will be using these methods in our implementation.
getForObject(url, T.class) : It retrieves an entity using HTTP GET method on the given URL and returns T. It doesn't return Status, Header params but only Response Body.
getForEntity(url, T.class) : It retrieves an entity by using HTTP GET method for the given URL and returns ResponseEntity<T>.
What is difference between postForObject() and postForEntity() ?
postForObject(url, request, T.class) : It saves an entity using HTTP POST method on the given URL and returns T. It doesn't return Status, Header params but only Response Body.
postForEntity(url, request, T.class) : It saves an entity by using HTTP POST method for the given URL and returns ResponseEntity<T>.
What is exchange() method in RestTemplate used for ?
exchange() method supports making call to any Http method (GET/POST/PUT/DELETE/…..). Generally, it has below syntax.
exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object… uriVariables): ResponseEntity<T>
url : Producer application URL (RestController's mrthod path)
HttpMethod : is an enum to provide method type.
HttpEntity : Request Body + HttpHeaders (it can also be null)
responseType : Class type of response
Object-var/args : used for sending multiple pathVariables
What is the format of data Consumer Application receives from Producer Application ?
If any RestController's method returns a non-String type i.e. class or collection type then Data is converted into JSON format and provided to Consumer Application. Consumer application reads that data as a String (JSON is also a String only).
What all parameters are expected to write consumer methods in RestTemplate ?
In fact consumer method could be predictable on the already existing producer method. The producer method's url, return type, Http method type, path variables etc. will decide the structure of your consumer method. Generally we expect following things to pass as parameters to RestTemplate's methods.
- URL of Producer webservice
- Body of the request (in case of POST/PUT…)
- Media Type like APPLICATION_JSON, APPLICATION_XML, APPLICATION_PDF etc. (in case of POST/PUT…)
- Http Method type
- Return type of producer method
- Path Variables (If any)
How to implement RestTemplate methods ?
Although we will take reference of REST API producer application that we developed in previous articles and call the already existing methods with the help of RestTemplate. Here, we are considering "Invoice" as our model class. Besides exchange() method, we will take one more alternate method to develop the template operations. Alternate method is commented in below code. Afterwards You can un-comment the same as per your requirement to test it accordingly.
Save Invoice
saveInv()
private void saveInv() { // 1. Producer application URL String url = "http://localhost:8080/api/invoices"; // Send JSON data as Body String body = "{\"name\":\"INV11\", \"amount\":234.11,\"number\":\"INVOICE11\",\"receivedDate\":\"28-10-2020\",\"type\":\"Normal\",\"vendor\":\"ADHR001\",\"comments\" :\"On Hold\"}"; // Http Header HttpHeaders headers = new HttpHeaders(); //Set Content Type headers.setContentType(MediaType.APPLICATION_JSON); //requestEntity : Body+Header HttpEntity<String> request = new HttpEntity<String> (body,headers); // 2. make HTTP call and store Response (URL,ResponseType) // ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class); ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST,request, String.class); // 3. Print details(body,status..etc) logger.info("Response Body : {}", response.getBody()); logger.info("Status code value : {}", response.getStatusCodeValue()); logger.info("Status code : {}", response.getStatusCode().name()); }
Output:
Output
Response Body : Invoice '9' created Status code value : 201 Status code : OK
Get All Invoices
getAllInvoices()
private void getAllInvoices() { String url = "http://localhost:8080/api/invoices"; ResponseEntity<Invoice[]> response = restTemplate.getForEntity(url,Invoice[].class); // ResponseEntity<Invoice[]> response = restTemplate.exchange(url, HttpMethod.GET, null, Invoice[].class); Invoice[] invs = response.getBody(); List<Invoice> list = Arrays.asList(invs); logger.info("Response Body : {}", list); logger.info("Status code value : {}", response.getStatusCodeValue()); logger.info("Status code : {}", response.getStatusCode().name()); logger.info("Headers {} :", response.getHeaders()); }
Output:
output
Response Body : [Invoice(id=1, name=Inv1, amount=135.0, finalAmount=148.5, number=Inv02345, receivedDate=14-10-2020, type=normal, vendor=Vend2, comments=Ok), Invoice(id=2, name=Inv1, amount=135.0, finalAmount=148.5, number=Inv0234, receivedDate=14-10-2020, type=normal, vendor=Vend2, comments=on Hold), Invoice(id=3, name=Inv1, amount=135.0, finalAmount=148.5, number=Inv0234, receivedDate=14-10-2020, type=normal, vendor=Vend2, comments=on Hold), Invoice(id=4, name=Inv11, amount=124.0, finalAmount=null, number=Inv023411, receivedDate=24-10-2020, type=urgent, vendor=Vend24, comments=on Hold), Invoice(id=5, name=INV11, amount=234.11, finalAmount=257.521, number=INVOICE11, receivedDate=28-10-2020, type=null, vendor=null, comments=null), Invoice(id=7, name=INV11, amount=888.0, finalAmount=976.8, number=INVOICE11, receivedDate=28-10-2020, type=null, vendor=null, comments=null), Invoice(id=8, name=INV11, amount=234.11, finalAmount=257.521, number=INVOICE11, receivedDate=28-10-2020, type=Normal, vendor=ADHR001, comments=On Hold), Invoice(id=9, name=INV11, amount=234.11, finalAmount=257.521, number=INVOICE11, receivedDate=28-10-2020, type=Normal, vendor=ADHR001, comments=On Hold)] Status code value : 200 Status code : CREATED Headers [Content-Type:"application/json", Transfer-Encoding:"chunked", Date:"Thu, 29 Oct 2020 15:39:09 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"] :
Get One Invoice
getOneInvoice()
private void getOneInvoice() { String url = "http://localhost:8080/api/invoices/{id}"; // ResponseEntity<String> response= restTemplate.getForEntity(url, String.class, 9); ResponseEntity<String> response= restTemplate.exchange(url, HttpMethod.GET, null, String.class, 7); logger.info("Response Body : {}", response.getBody()); logger.info("Status code value : {}", response.getStatusCodeValue()); logger.info("Status code : {}",response.getStatusCode().name()); }
Output:
output
Response Body : {"id":9,"name":"INV11","amount":234.11,"finalAmount":257.521,"number":"INVOICE11","receivedDate":"28-10-2020","type":"Normal","vendor":"ADHR001","comments":"On Hold"} Status code value : 200 Status code : OK
Update Invoice
updateInvoice()
private void updateInvoice() { String url = "http://localhost:8080/api/invoices/{id}"; String body = "{\"name\":\"INV13\",\"amount\":888}"; // Request Header HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); // requestEntity = Body + header HttpEntity<String> requestEntity = new HttpEntity<String>(body, headers); // restTemplate.put(url, requestEntity, 7); ResponseEntity<String> response= restTemplate.exchange(url, HttpMethod.PUT, requestEntity, String.class, 7); logger.info("Response Body : {}", response.getBody()); logger.info("Status code value : {}", response.getStatusCodeValue()); logger.info("Status code : {}",response.getStatusCode().name()); logger.info("Response Headers : {}", response.getHeaders()); }
Output:
output
Response Body : null Status code value : 205 Status code : RESET_CONTENT Response Headers : [Content-Length:"0", Date:"Thu, 29 Oct 2020 15:43:27 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]
Delete Invoice
deleteInvoice()
private void deleteInvoice() { String url = "http://localhost:8080/api/invoices/{id}"; // restTemplate.delete(url, 6); ResponseEntity<String> response= restTemplate.exchange(url, HttpMethod.DELETE, null, String.class,5); logger.info("Response Body : {}", response.getBody()); logger.info("Status code value : {}", response.getStatusCodeValue()); logger.info("Status code : {}",response.getStatusCode().name()); logger.info("Response Headers : {}", response.getHeaders()); }
Output:
output
Response Body : Invoice '5' deleted Status code value : 200 Status code : OK Response Headers : [Content-Type:"text/plain;charset=UTF-8", Content-Length:"19", Date:"Thu, 29 Oct 2020 15:46:56 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]
Complete Code
We created one Spring Boot Starter Project named "SpringBootRestTemplate" with dependencies 'Lombok' and 'Spring Web'. Still if you are new to SpringBoot & Lombok, visit internal links as SpringBoot & Lombok accordingly. Furthermore, in the main class(SpringBootRestTemplateApplication.java) we wrote code of RestTemplate object creation and utilized it via auto-wiring. Besides this modification, we created two new classes Invoice.java(Model class) and a Runner class RestTemplateRunner.java(class having all methods). From the run() method of RestTemplateRunner.java uncomment the respective method required to test accordingly. In the end, Project structure will look like below screenshot.
SpringBootRestTemplateApplication.java
package com.dev.springboot.rest.template; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication public class SpringBootRestTemplateApplication { public static void main(String[] args) { SpringApplication.run(SpringBootRestTemplateApplication.class, args); } @Bean public RestTemplate getRestTemplate() { return new RestTemplate(); } }
Invoice.java
package com.dev.springboot.rest.template.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class Invoice { private Long id; private String name; private Double amount; private Double finalAmount; private String number; private String receivedDate; private String type; private String vendor; private String comments; }
RestTemplateRunner.java
package com.dev.springboot.rest.template.runner; import java.util.Arrays; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import com.dev.springboot.rest.template.entity.Invoice; @Component public class RestTemplateRunner implements CommandLineRunner { private Logger logger = LoggerFactory.getLogger(RestTemplateRunner.class); @Autowired RestTemplate restTemplate; @Override public void run(String... args) throws Exception { saveInv(); // getAllInvoices(); // getOneInvoice(); // updateInvoice(); // deleteInvoice(); } private void saveInv() { // 1. Producer application URL String url = "http://localhost:8080/api/invoices"; // Send JSON data as Body String body = "{\"name\":\"INV11\", \"amount\":234.11,\"number\":\"INVOICE11\",\"receivedDate\":\"28-10-2020\",\"type\":\"Normal\",\"vendor\":\"ADHR001\",\"comments\" :\"On Hold\"}"; // Http Header HttpHeaders headers = new HttpHeaders(); //Set Content Type headers.setContentType(MediaType.APPLICATION_JSON); //requestEntity : Body+Header HttpEntity<String> request = new HttpEntity<String> (body,headers); // 2. make HTTP call and store Response (URL,ResponseType) // ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class); ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST,request, String.class); // 3. Print details(body,status..etc) logger.info("Response Body : {}", response.getBody()); logger.info("Status code value : {}", response.getStatusCodeValue()); logger.info("Status code : {}", response.getStatusCode().name()); } private void getAllInvoices() { String url = "http://localhost:8080/api/invoices"; ResponseEntity<Invoice[]> response = restTemplate.getForEntity(url,Invoice[].class); // ResponseEntity<Invoice[]> response = restTemplate.exchange(url, HttpMethod.GET, null, Invoice[].class); Invoice[] invs = response.getBody(); List<Invoice> list = Arrays.asList(invs); logger.info("Response Body : {}", list); logger.info("Status code value : {}", response.getStatusCodeValue()); logger.info("Status code : {}", response.getStatusCode().name()); logger.info("Headers {} :", response.getHeaders()); } private void getOneInvoice() { String url = "http://localhost:8080/api/invoices/{id}"; // ResponseEntity<String> response= restTemplate.getForEntity(url, String.class, 9); ResponseEntity<String> response= restTemplate.exchange(url, HttpMethod.GET, null, String.class, 7); logger.info("Response Body : {}", response.getBody()); logger.info("Status code value : {}", response.getStatusCodeValue()); logger.info("Status code : {}",response.getStatusCode().name()); } private void updateInvoice() { String url = "http://localhost:8080/api/invoices/{id}"; String body = "{\"name\":\"INV13\",\"amount\":888}"; // Request Header HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); // requestEntity = Body + header HttpEntity<String> requestEntity = new HttpEntity<String>(body, headers); // restTemplate.put(url, requestEntity, 7); ResponseEntity<String> response= restTemplate.exchange(url, HttpMethod.PUT, requestEntity, String.class, 7); logger.info("Response Body : {}", response.getBody()); logger.info("Status code value : {}", response.getStatusCodeValue()); logger.info("Status code : {}",response.getStatusCode().name()); logger.info("Response Headers : {}", response.getHeaders()); } private void deleteInvoice() { String url = "http://localhost:8080/api/invoices/{id}"; // restTemplate.delete(url, 6); ResponseEntity<String> response= restTemplate.exchange(url, HttpMethod.DELETE, null, String.class,5); logger.info("Response Body : {}", response.getBody()); logger.info("Status code value : {}", response.getStatusCodeValue()); logger.info("Status code : {}",response.getStatusCode().name()); logger.info("Response Headers : {}", response.getHeaders()); } }
How to test the application ?
To run the application for testing , right click on Project then select Run As >> Spring Boot App. Additionally, please uncomment the respective method called in run() of RestTemplateRunner.java to test the methods one by one. Further you can verify your output by comparing the output given in previous section.
How to convert ResponseEntity to Java object ?
Sometimes many developers face issue in converting ResponseEntity to Java Objects. Although this part is somewhat tricky. Further, in order to clarify this problem, here we will discuss three solutions to get it done.
Solution#1 : By using getForEntity() method and returning Array Of Objects
ResponseEntity<Invoice[]> response = restTemplate.getForEntity( url , Invoice[].class); Invoice[] invs = response .getBody(); List<Invoice> list = Arrays.asList( invs ); System.out.println("Response Body : " + list );
Solution #2 : By using exchange() method and returning List Of Objects
ResponseEntity<List<Invoice>> response = restTemplate.exchange( url , HttpMethod. GET , null, new ParameterizedTypeReference<List<Invoice>>() {}); List<Invoice> list = response .getBody(); System.out.println("Response Body : " + list );
Solution #3 : By using exchange() method and returning Array Of Objects
ResponseEntity<Invoice[]> response = restTemplate.exchange(url, HttpMethod.GET, null, Invoice[].class); Invoice[] invs = response .getBody(); List<Invoice> list = Arrays.asList( invs ); System.out.println("Response Body : " + list );
Moreover, we can use any solution to get it done based on our requirement and scenario. Furthermore, in order to get complete code implementation, visit getAllInvoices() method of this article.
Summary
Almost every REST application will have these operations we learnt in this article. In other words, no REST API can be developed without these operations. So, you have learnt the mandatory concepts of 'How to write REST Consumer API using Spring Boot RestTemplate'. In addition, for further learning on RestTemplate, kindly visit official site. Also in upcoming articles we will be learning other types of REST Clients.
0 Response to "Consume Rest Service Java Example Resttemplate"
Post a Comment