Spring Boot RestTemplate
last modified July 28, 2023
Spring Boot RestTemplate tutorial shows how to use RestTemplate to
create synchronous HTTP requests in a Spring application.
Spring is a popular Java application framework and Spring Boot is an evolution of Spring that helps create stand-alone, production-grade Spring based applications easily.
RestTemplate
RestTemplate is a synchronous client to perform HTTP requests. It
uses a simple, template method API over underlying HTTP client libraries such as
the JDK HttpURLConnection, Apache HttpComponents, and others.
Since Spring 5.0, a new client WebClient is available that can be
use do create both synchronous and asynchronous requests. In the future
releases, RestTemplate will be deprecated in favour of
WebClient.
Spring Boot RestTemplate example
In the following application we create a custom test server that produces
JSON data and use RestTemplate to generate a HTTP request and consume
the returned JSON data.
Creating JSON server
We use Node to create a JSON test server for our purposes.
$ node --version v20.4.0
We show the version of Node.
$ npm init -y $ npm i -g json-server $ npm i @faker-js/faker fs
We initialize a Node projet and install json-server,
faker, and fs modules. The json-server is
used to create a test JSON server, faker to generate test data, and
fs to work with filesystem in JavaScript.
import { faker } from '@faker-js/faker';
import { writeFileSync } from 'fs'
function generateUsers() {
    let users = []
    for (let id=1; id <= 100; id++) {
        let firstName = faker.person.firstName()
        let lastName = faker.person.lastName()
        let email = faker.internet.email()
        users.push({
            "id": id,
            "first_name": firstName,
            "last_name": lastName,
            "email": email
        })
    }
    return { "users": users }
}
let dataObj = generateUsers();
writeFileSync('data.json', JSON.stringify(dataObj, null, '\t'));
With faker we generate one hundred users with id, first name, last name, and
email attributes. The data is written to data.json  file. The file
is used by json-server.
$ node generate_fake_users.js
We generate one hundred fake users.
$ json-server --watch data.json
\{^_^}/ hi!
Loading data.json
Done
Resources
http://localhost:3000/users
Home
http://localhost:3000
We start the json-server. Now we can create a request to the
http://localhost:3000/users resource to get one hundred users in
JSON.
Spring Boot application
We create a Spring Boot application. We need the following Maven dependencies and plugins:
spring-boot-starter, spring-web, jackson-databind,
spring-boot-starter-test, and spring-boot-maven-plugin.
spring.main.banner-mode=off
logging.level.root=INFO
logging.pattern.console=%d{dd-MM-yyyy HH:mm:ss} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n
myrest.url=http://localhost:3000/users
The application.properties is the main configuration file in Spring Boot.
We turn off the Spring banner, set the logging level to info, and set the
console logging pattern. We also set an URL property which points to the users resource.
The property is going to be later retrieved with @Value.
package com.zetcode.model;
import com.fasterxml.jackson.annotation.JsonProperty;
public class User {
    private int id;
    private String firstName;
    private String lastName;
    private String email;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getFirstName() {
        return firstName;
    }
    @JsonProperty("first_name")
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    @JsonProperty("last_name")
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    @Override
    public String toString() {
        final var sb = new StringBuilder("User{");
        sb.append("id=").append(id);
        sb.append(", firstName='").append(firstName).append('\'');
        sb.append(", lastName='").append(lastName).append('\'');
        sb.append(", email='").append(email).append('\'');
        sb.append('}');
        return sb.toString();
    }
}
The User bean maps to the JSON user object. Spring uses Jackson
library to bind JSON data to Java classes. Since the JSON attributes do not
match the Java attributes, we use @JsonProperty to fix this.
package com.zetcode.config;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;
@Configuration
public class AppConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofMillis(3000))
                .setReadTimeout(Duration.ofMillis(3000))
                .build();
    }
}
We create a configuration bean with RestTemplateBuilder. It sets up
the RestTemplate. We set the connection and read timeouts.
package com.zetcode.service;
import com.zetcode.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class MyRestService {
    private final RestTemplate myRestTemplate;
    @Value("${myrest.url}")
    private String restUrl;
    @Autowired
    public MyRestService(RestTemplate myRestTemplate) {
        this.myRestTemplate = myRestTemplate;
    }
    public User[] getUsers() {
        return myRestTemplate.getForObject(restUrl, User[].class);
    }
}
MyRestService is the service class that generates the HTTP request.
It fetches all users from the JSON test server.
@Autowired
public MyRestService(RestTemplate myRestTemplate) {
    this.myRestTemplate = myRestTemplate;
}
We inject the RestTemplate bean.
@Value("${myrest.url}")
private String restUrl;
From the configuration, we get the URL using @Value annotation.
var users = myRestTemplate.getForObject(restUrl, User[].class);
We use the getForObject method to generate the request.
Since we expect an array of objects, we use User[].class syntaxs.
package com.zetcode;
import com.zetcode.service.MyRestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class MyRunner implements CommandLineRunner {
    private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);
    private final MyRestService myRestService;
    @Autowired
    public MyRunner(MyRestService myRestService) {
        this.myRestService = myRestService;
    }
    @Override
    public void run(String... args) throws Exception {
        var users = myRestService.getUsers();
        Arrays.stream(users).limit(10).forEach(todo -> logger.info("{}", todo));
    }
}
MyRunner uses the MyRestService to get the users.
We show first ten users to the console.
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
Application is the entry point which sets up Spring Boot
application.
package com.zetcode;
import com.zetcode.config.AppConfig;
import com.zetcode.service.MyRestService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
@RestClientTest(value = {MyRestService.class, AppConfig.class})
public class ApplicationTests {
    @Autowired
    private MyRestService service;
    @Test
    public void usersNotEmpty() throws Exception {
        var users = this.service.getUsers();
        assertThat(users).isNotEmpty();
    }
    @Test
    public void hasSizeOneHundred() throws Exception {
        var users = this.service.getUsers();
        assertThat(users).hasSize(100);
        System.out.println(Arrays.toString(users));
    }
}
We test the getUsers service method. We test that the JSON data is
not empty and that it contains one hundred elements.
@RestClientTest(value={MyRestService.class, AppConfig.class})
The @RestClientTest annotation is used to test Spring rest clients.
It disables full auto-configuration and applies only configuration relevant to
rest client tests.
$ ./gradlew bootRun
...
... - User{id=1, firstName='Ofelia', lastName='Hintz', email='Gustave.Von43@yahoo.com'}
... - User{id=2, firstName='Brian', lastName='Marvin', email='Marina.Shields@hotmail.com'}
... - User{id=3, firstName='Adah', lastName='Marquardt', email='Osbaldo_Halvorson55@hotmail.com'}
... - User{id=4, firstName='Jaycee', lastName='Kulas', email='Claud85@gmail.com'}
...
We run the application.
In this article we have shown how to use RestTemplate to create
synchronous requests in a Spring application. The REST data came from a test
JSON server created by Node.