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'
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:
- A RestTemplate instance is autowired in using field injection.
- The
main()method is standard for a Spring application start-up. - The
run()method constructs a bean that will get picked up by Spring. However, it's a little different from most. Spring recognizes theCommandLineRunnerreturn 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 fromhttps://zenquotes.io/api/random/and assign it torandomQuote. - Print the quote now stored in
randomQuoteto the console.
Not too bad, right? Once you have the data mapped to the POJO, it's really just back to regular Java programming.
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 ofgetForObject(). -
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
responseEntityusinggetBody().
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:
- Add placeholders denoted by curly braces to your URL.
- Place parameters in a
Map<String, String>. - 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
Mapof multiple params (as mentioned above), and pass it togetForEntity().
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
CommandLineRunnerbean 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.