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.