You are here
Home > java >

How to write REST Consumer API using Spring Boot RestTemplate

How to write REST Consumer API using Spring Boot RestTemplateApart 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’.

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 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.

  1. URL of Producer webservice
  2. Body of the request (in case of POST/PUT…)
  3. Media Type like APPLICATION_JSON, APPLICATION_XML, APPLICATION_PDF  etc. (in case of POST/PUT…)
  4. Http Method type
  5. Return type of producer method
  6. 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. An alternate method is commented in below code. Afterwards, you can un-comment the same as per your requirement to test it accordingly. Let’s implement the concept ‘How to write REST Consumer API using Spring Boot RestTemplate’ step by step.

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: How to write REST Consumer API using Spring Boot RestTemplate?

Let’s write the complete code for our topic ‘How to write REST Consumer API using Spring Boot RestTemplate’. 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.

How to write REST Consumer API using Spring Boot : RestTemplate

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 the 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.

FAQ

What is the difference between RestTemplate and WebClient in Spring Boot?

WebClient is a more modern and flexible option to RestTemplate. WebClient is introduced in Spring WebFlux. It is asynchronous by nature and is a better choice for non-blocking, reactive applications. RestTemplate is a synchronous client and is more appropriate for traditional Spring MVC/REST applications.

Should I use WebClient in place of RestTemplate in Spring Boot projects?

RestTemplate was considered as a mature technology. However, WebClient was recommended for new projects and for applications that require non-blocking, reactive behavior. Moreover, people are still using RestTemplate in some legacy projects. Be sure to check the latest Spring Boot documentation and community discussions for any updates on the status of RestTemplate.

Can I use RestTemplate to perform synchronous and parallel requests to multiple endpoints?

Yes, RestTemplate offers us to make synchronous requests to multiple endpoints in parallel by leveraging Java’s concurrency mechanisms, such as threads or CompletableFuture. We can create multiple RestTemplate instances or use a single RestTemplate carefully in a multi-threaded environment to accomplish parallelism.

Is RestTemplate suitable for microservices communication within a Spring Boot-based microservices architecture?

We can use RestTemplate for microservices communication, but we should consider using technologies like Spring Cloud OpenFeign, which provide higher-level abstractions and better integration with service discovery and load balancing features in microservices architectures. These technologies can simplify inter-service communication in a microservices environment.

Conclusion

Almost every REST application will have these operations, that we learnt in this article. In simple words, no REST API can be developed without these operations. So, you have learned the mandatory concepts of ‘How to write REST Consumer API using Spring Boot RestTemplate’. Now, you should be able to work on ‘How to write REST Consumer API using Spring Boot RestTemplate’. In addition, for further learning on RestTemplate, kindly visit official site. If you want to create REST client API using WebClient, kindly visit our separate article on ‘How To Use WebClient in Spring Boot‘. Also, in upcoming articles we will be learning other types of REST Clients.

Leave a Reply


Top