10) Spring Web Lesson

Spring RestTemplate: GET Requests

14 min to complete · By Ryan Desmond, Jared Larsen

As promised, this lesson will guide you through setting up a simple Spring Boot application that requests quotes from the Zen Quotes API. To accomplish this, you will use the RestTemplate class, a powerful tool provided by Spring Web. But what is Spring Web?

Spring Web is part of the larger Spring Framework, providing a comprehensive stack for building web applications. Spring Web simplifies many of the complexities of web development, allowing you to focus more on functionality. The RestTemplate class itself is designed for client-side HTTP access, and it makes interacting with web services like the Zen Quotes API a breeze!

Example Location:
com.codingnomads.springweb.resttemplate.GET

Spring Web Dependency

You must import the Spring Web dependency to access the RestTemplate class. If your project is using Maven, copy this into the pom.xml file. Make sure to place it between the <dependencies> tags.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

If you're using Gradle, add this to "dependencies" in your build.gradle file:

implementation 'org.springframework.boot:spring-boot-starter-web'
Colorful illustration of a light bulb

Note: This dependency is already present in your labs project, so this is only necessary if building a separate project. In that case, don't forget to "reload" your Maven/Gradle config so the new dependency is downloaded and added to your project.

Project Setup

The first thing to do is make a RestTemplate bean available for dependency injection. To accomplish this, you'll create a configuration class:

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }
}

Since this class is annotated with @Configuration, Spring will scan it for bean definitions. The restTemplate() method is annotated with @Bean, which signals Spring to create a bean and make it available in the container. Now, take a look at the demo bootstrapping class below.

@SpringBootApplication
public class GetForObjectDemo {

    @Autowired
    RestTemplate restTemplate;

    public static void main(String[] args) {
        SpringApplication.run(GetForObjectDemo.class, args);
    }

    @Bean
    public CommandLineRunner run() {
        return args -> {
            // this will run after Spring startup
        };
    }
}

This class does three things:

  1. A RestTemplate instance is autowired in using field injection.
  2. The main() method is standard for a Spring application start-up.
  3. The run() method constructs a bean that will get picked up by Spring. However, it's a little different from most. Spring recognizes the CommandLineRunner return type, causing it to be run directly after application startup.

Don't forget the POJO

In the last lesson, you checked out the JSON returned by the Zen Quotes API and learned how to model a POJO based on it. Since you'll see it referenced here, it's worth showing again. For simplicity, it contains one String field named q, which matches the key of the string returned by the Zen Quotes API.

@Data
public class QuoteTemplate {
    private String q;
}

Using Spring RestTemplate

The RestTemplate class is the key to making HTTP requests through your code. Even though it is possible to make requests through code without Spring or the RestTemplate class, doing this requires a lot of boilerplate which RestTemplate takes off your hands. There's no reason to opt for the long workaround instead of RestTemplate. To provide the required functionality, RestTemplate exposes several methods for you to use. The most important ones are discussed here:

getForObject() Example

The getForObject() method is used to submit GET requests using HTTP. It will then map the returned data directly onto an object. This method is overloaded to give a few ways of formatting your request. The most basic version is shown below:

public<T> T getForObject(URI url,Class<T> responseType)

This method takes in a URL and a responseType. The URL you pass in determines where the request for the resource will be sent, and the responseType parameter determines what class the returned information should be mapped to. As you can see, this method is generic, and it will return an instance of which ever class you pass in as the responseType parameter. Here it is in action:

@Bean
public CommandLineRunner run() throws Exception {
    return args -> {
        QuoteTemplate[] randomQuote;
        randomQuote = restTemplate.getForObject(
            "https://zenquotes.io/api/random/", QuoteTemplate[].class);
        System.out.println(Arrays.toString(randomQuote));
    };
}

Step by step, here are the innards of this method:

  • Create an array of the object type QuoteTemplate under the name randomQuote.
  • Use the getForObject() method to retrieve a quote from https://zenquotes.io/api/random/ and assign it to randomQuote.
  • Print the quote now stored in randomQuote to the console.

Not too bad, right? Once you have the data mapped to the POJO, it's really just back to regular Java programming.

Illustration of a lighthouse

Note: This example does not include error handling, so if a quote isn't returned for any reason, calling the toString() method on a null object would trigger a NullPointerException. It works for illustration purposes, but errors should always be accounted for by using try/catch blocks, null checks, etc.

Learn by Doing

Package: springweb.resttemplate.GET.getForObject

Time to submit more GET requests using RestTemplate!

  • Visit the Excuser API.
  • Familiarize yourself with its JSON response, and create a POJO to map it.
  • Now, use the RestTemplate instance in GetForObjectDemo to submit a GET request.
  • This might be tricky - pay special attention to the response structure.
  • Great job! Now, submit a few more requests using the available count and category path variables.

getForEntity() Example

Sometimes, you will find yourself in a situation where you need more information about the response from the server. You may need to access headers or confirm the status code before taking additional action. The getForObject() method doesn't support this, luckily the getForEntity() method does.

The key difference between these methods is that getForObject() returns an object mapped from the data directly, whereas getForEntity() returns the object embedded within a ResponseEntity<?> object. ResponseEntity also stores a bunch of extra information about the response. This is very helpful and is why you'll commonly opt to use getForEntity() moving forward. Here it is in the context of the Zen Quotes API quote retrieval:

ResponseEntity<QuoteTemplate[]> responseEntity =
    restTemplate.getForEntity(
        "https://zenquotes.io/api/random", QuoteTemplate[].class);

if (responseEntity.getStatusCode().equals(HttpStatus.OK) 
        && responseEntity.getBody() != null) {
    QuoteTemplate[] quoteTemplate = responseEntity.getBody();
    System.out.println(Arrays.toString(quoteTemplate));
} else {
    System.out.println("Something went wrong! " +
        "The response was not marked with status code 200");
}

The main differences here are:

  • Wrapped Return: The code defines a ResponseEntity with an embedded QuoteTemplate[].

  • RestTemplate Method: The code calls getForEntity() instead of getForObject().

  • Response Metadata: The code uses fields in the ResponseEntity object to confirm the status of the request.

  • Response Body: The code accesses the QuoteTemplate[] within responseEntity using getBody().

Request Parameters

As you are aware, many APIs make use of path variables and query parameters like so: www.example.com/users/100?format=json&api-key=12345 When using RestTemplate to submit requests, it is possible to pass in parameters as a method argument. This means that instead of manually concatenating your parameters into your URL string, you can add them to a Map and pass them in as the third method parameter for both getForEntity() and getForObject(). To do this, you'll need to:

  1. Add placeholders denoted by curly braces to your URL.
  2. Place parameters in a Map<String, String>.
  3. Pass the params to the RestTemplate call.
String URL = "api.com/users/{userId}?format={format}&api-key={apiKey}";

Map<String, String> params = new HashMap<>();
params.put("userId", "100");
params.put("format", "json");
params.put("apiKey", 12345);

ResponseEntity<User> response =
        restTemplate.getForEntity(URL, User.class, params);

This is a simple and versatile approach to handling URL parameters in RestTemplate requests.

Learn by Doing

Package: springweb.resttemplate.GET.getForEntity

This time around, you will utilize The Bored API.

  • Again, create a POJO to map the response.
  • What's different here is that this API utilizes query parameters.
  • Read the documentation and submit a few requests using params.
  • Now, build a Map of multiple params (as mentioned above), and pass it to getForEntity().

Right on! Be sure to push your work to GitHub when you're done.

Summary: GET Requests with Spring RestTemplate

You now have a near-unlimited supply of inspirational quotes, excuses for work/school, and things to do when bored! This is clearly all very important information, but even more critical is what this lesson helped you accomplish:

  • Setting up a CommandLineRunner bean for logic execution after Spring startup (this comes in handy down the road!)
  • Using getForObject() to submit a GET request to an external API, and have a POJO populated with data from the response body.
  • Using getForEntity() to submit a GET request and access additional information about the response and the body.