Ebooks

Spring Boot RestTemplate

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

We show the version of Node.

$ npm init    
$ npm i -g json-server
$ npm i 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.

generate_fake_users.js
const faker = require('faker')
const fs = require('fs')

function generateUsers() {

    let users = []

    for (let id=1; id <= 100; id++) {

        let firstName = faker.name.firstName()
        let lastName = faker.name.lastName()
        let email = faker.internet.email()

        users.push({
            "id": id,
            "first_name": firstName,
            "last_name": lastName,
            "email": email
        })
    }

    return { "users": users }
}

let dataObj = generateUsers();

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

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

User.java
package com.zetcode.bean;

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.

AppConfig.java
package com.zetcode.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate() {

        var factory = new SimpleClientHttpRequestFactory();

        factory.setConnectTimeout(3000);
        factory.setReadTimeout(3000);

        return new RestTemplate(factory);
    }
}

We create a configuration bean. It sets up the RestTemplate. The SimpleClientHttpRequestFactory is used to set the connection and read timeouts.

AppConfig.java
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();
    }
}

Alternatively, we can use the RestTemplateBuilder to do the job.

MyRestService.java
package com.zetcode.service;

import com.zetcode.bean.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 {

    @Autowired
    private RestTemplate myRestTemplate;

    @Value("${myrest.url}")
    private String restUrl;

    public User[] getUsers() {

        var users = myRestTemplate.getForObject(restUrl, User[].class);

        return users;
    }
}       

MyRestService is the service class that generates the HTTP request. It fetches all users from the JSON test server.

@Autowired
private RestTemplate 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.

MyRunner.java
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);

    @Autowired
    private 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.

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

ApplicationTests.java
package com.zetcode;

import com.zetcode.config.AppConfig;
import com.zetcode.service.MyRestService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringRunner.class)
@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(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.

$ mvn -q spring-boot:run
...
27-11-2018 15:33:55 [main] INFO  com.zetcode.MyRunner.lambda$run$0 - User{id=1, firstName='Ofelia', lastName='Hintz', email='Gustave.Von43@yahoo.com'}
27-11-2018 15:33:55 [main] INFO  com.zetcode.MyRunner.lambda$run$0 - User{id=2, firstName='Brian', lastName='Marvin', email='Marina.Shields@hotmail.com'}
27-11-2018 15:33:55 [main] INFO  com.zetcode.MyRunner.lambda$run$0 - User{id=3, firstName='Adah', lastName='Marquardt', email='Osbaldo_Halvorson55@hotmail.com'}
27-11-2018 15:33:55 [main] INFO  com.zetcode.MyRunner.lambda$run$0 - User{id=4, firstName='Jaycee', lastName='Kulas', email='Claud85@gmail.com'}
...

We run the application.

In this tutorial, 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. You might also be interested in the related tutorials: Spring Boot @RestController tutorial, Spring Boot H2 REST tutorial, Spring Boot RESTFul application, Spring Boot REST Data JPA tutorial, and Java tutorial.