Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 54

Synchronous HTTP with RestTemplate

Recommended resources

Hello!

In our last lesson, we successfully refactored a monolithic application into separate, independent microservices for Company, Job, and Review. While this independence is a core tenet of microservice architecture, it also introduces a challenge: our services are now isolated. For example, our Job service holds a companyId, but it has no way to retrieve the actual details of the corresponding company.

Today, we'll bridge that gap by exploring inter-service communication. This lesson focuses on the first and most straightforward method in the Spring ecosystem: using RestTemplate to make synchronous, blocking HTTP calls between services. We will learn how to make our Job service communicate with our Company service to fetch the data it needs.

1. Inter-Service Communication and RestTemplate

In a microservice architecture, services need to talk to each other to fulfill business requests. This communication can happen in two primary ways: synchronously (the caller waits for a response) or asynchronously (the caller sends a message and moves on).

RestTemplate is Spring's primary tool for synchronous communication. It's a client that simplifies the process of making HTTP requests to external REST APIs.

To understand the context and fundamentals of RestTemplate, let's start with a short video.

Inter-service Communication using RestTemplate | Spring Boot REST API to Microservices | Video #8

This video from EmbarkX introduces the concept of inter-service communication and explains the role of RestTemplate within the Spring framework.

Watch from 02:05 to 11:35. Pay attention to the distinction between synchronous and asynchronous communication and the key features of RestTemplate, such as its blocking nature and abstraction over low-level HTTP details.

As the video explained, RestTemplate is a powerful abstraction. It handles the details of making HTTP requests and, crucially, can automatically convert the JSON or XML response from an API into a Java object (a POJO).

From a system design perspective, it's useful to see where RestTemplate fits.

RestTemplate Overview Diagram
This diagram illustrates the internal components of `RestTemplate`. Your application code uses `RestTemplate`, which in turn uses `HttpMessageConverter` (like Jackson) to serialize/deserialize data. It sends the request via a `ClientHttpRequestFactory` and can use a `ResponseErrorHandler` for custom error handling.

2. Making a Synchronous Call with RestTemplate

Let's put this into practice. We'll continue with the microservices we defined in the previous lesson. Our goal is to make the Job service call the Company service's GET /companies/{id} endpoint to retrieve details for a job posting.

The following video demonstrates exactly this scenario. It shows the initial, most direct way to implement this call.

Inter-service Communication using RestTemplate | Spring Boot REST API to Microservices | Video #8

Continuing with the same project from our last lesson, this segment shows the hands-on implementation of a RestTemplate call from the Job service to the Company service.

Watch from 11:35 to 20:23. The key steps are: creating a RestTemplate instance, using the getForObject() method, and defining a local POJO to map the response.

Let's break down the process shown in the video.

Key Implementation Steps:

  1. Instantiate RestTemplate:
    A RestTemplate object is created.

    RestTemplate restTemplate = new RestTemplate();
    
  2. Define the Target URL:
    The full URL of the endpoint you want to call is specified. For now, this is hardcoded.
    "http://localhost:8081/companies/1"

  3. Define a Local POJO:
    The Job microservice needs a Java class that mirrors the structure of the JSON response from the Company service. This is a critical point: this Company class is not a JPA entity. It's a simple Plain Old Java Object (POJO) used for data transfer. You'll often see these referred to as Data Transfer Objects (DTOs), which we'll cover more formally later.

    // In Job microservice
    public class Company {
        private Long id;
        private String name;
        private String description;
        // getters and setters...
    }
    
  4. Make the Call with getForObject():
    The getForObject() method makes a GET request and automatically deserializes the response body into an object of the specified class.

    // The URL of the company service endpoint
    String companyServiceUrl = "http://localhost:8081/companies/1";
    
    // Make the call
    Company company = restTemplate.getForObject(companyServiceUrl, Company.class);
    
    // Now you can use the company object
    System.out.println(company.getName());
    

This flow is visualized well in the following diagram, where one Spring Boot service uses RestTemplate to consume an endpoint from another.

Spring Boot Restful Client with RestTemplate Example
This diagram shows the interaction flow. A client (like Postman) calls Service A (`SpringBootRestTemplateDemo`), which then uses `RestTemplate` to make a synchronous call to Service B (`SpringBootDemo`) to get the data it needs.

3. A Better Way: Managing RestTemplate as a Spring Bean

The implementation we just saw works, but it has a significant drawback. Creating new RestTemplate() inside a service method for every request is inefficient. It creates unnecessary objects and misses out on the power of Spring's dependency injection container.

The standard and recommended practice is to create a single, shared instance of RestTemplate and manage it as a Spring bean.

12 Using a Bean to create RestTemplate instance - Spring Boot Microservices Level 1

The channel Java Brains provides a clear rationale for why creating RestTemplate as a bean is superior and demonstrates how to do it.

First, watch from 00:45 to 01:15 to understand the problem with the 'new' keyword. Then, watch from 01:15 to 04:14 to see the solution: defining a @Bean in a configuration class and injecting it with @Autowired.

The Recommended Approach:

  1. Create a Configuration Class:
    Create a new class and annotate it with @Configuration. This tells Spring that the class contains bean definitions.

    @Configuration
    public class AppConfig {
        // Bean definitions go here
    }
    
  2. Define the RestTemplate Bean:
    Inside your configuration class, create a method that returns a RestTemplate instance and annotate it with @Bean. Spring will execute this method once at startup and manage the returned object as a singleton bean.

    @Configuration
    public class AppConfig {
        @Bean
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }
    
  3. Inject the Bean:
    Now, in any service class where you need to make an HTTP call, you can simply ask Spring to inject the RestTemplate bean using constructor injection. This is the dependency injection pattern in action.

    @Service
    public class JobServiceImpl implements JobService {
    
        private final RestTemplate restTemplate;
    
        // Use @Autowired on the constructor for dependency injection
        @Autowired
        public JobServiceImpl(RestTemplate restTemplate) {
            this.restTemplate = restTemplate;
        }
    
        @Override
        public Job getJobById(Long id) {
            // ... find job from repository ...
            
            // Use the injected RestTemplate instance
            String companyServiceUrl = "http://localhost:8081/companies/" + job.getCompanyId();
            Company company = restTemplate.getForObject(companyServiceUrl, Company.class);
            
            // ... combine job and company info ...
            return job;
        }
    }
    

This approach is more efficient, aligns with Spring's design philosophy, and makes your code easier to test and configure.


4. RestTemplate Methods and Configuration

RestTemplate offers a family of methods for different use cases. While we focused on getForObject(), it's good to be aware of the others.

Complete Guide to Spring RestTemplate

The article 'Complete Guide to Spring RestTemplate' from Reflectoring provides a great summary of the most common methods.

Read the section titled 'Some Useful Methods of RestTemplate'. This provides a concise overview of methods like getForEntity, postForObject, and the versatile exchange.

A key takeaway from that reading is the difference between getForObject() and getForEntity().

  • getForObject(): Returns just the response body, mapped to your POJO. Simple and direct.
  • getForEntity(): Returns a ResponseEntity object, which wraps the response body and includes HTTP metadata like status codes and headers. This is useful when you need to programmatically check if the call was successful (e.g., status 200 OK) before processing the body.

Finally, in a production system, it's critical to configure timeouts for synchronous calls. A call to another service might hang, and you don't want your calling service to be blocked indefinitely, which can cause cascading failures. RestTemplate can be configured with connection and read timeouts. The Reflectoring article you just looked at covers this in the section "Configuring the HTTP Client in RestTemplate" if you wish to explore further.


Conclusion

In this lesson, we established our first communication channel between microservices. We learned how to use RestTemplate to make synchronous, blocking calls, enabling our Job service to enrich its data with information from the Company service.

Key Takeaways:

  • RestTemplate is Spring's synchronous REST client, abstracting away low-level HTTP details.
  • The getForObject() method makes a GET request and maps the JSON response directly to a Java POJO.
  • The calling service needs a local POJO (or DTO) to represent the data it expects to receive.
  • Best Practice: RestTemplate should be defined as a singleton @Bean in a @Configuration class and injected where needed, rather than being instantiated with new for each use.
  • Synchronous calls are inherently blocking. This is a simple model but can have performance and resilience implications in a large-scale distributed system.

The blocking nature of RestTemplate is its most significant characteristic and limitation. What if we could make a request without waiting, freeing up the thread to do other work until the response arrives? In our next lesson, we will explore exactly that by learning about WebClient, Spring's modern, non-blocking, and asynchronous client for making HTTP calls.