Calling REST service with Spring RestTemplate

In this screencast we will walk through how to call a RESTFul webservice in java with spring's RESTTemplate.

Detailed Video Notes

Getting started

As REST services continue to gain popularity you will be faced with question on whether or not you should make server side HTTP request or develop a native client. In this screen cast we will show how to make a RESTFul services request with spring's RESTTemplate.

What is a RestTemplate

[0:15]

RestTemplate is a class used to make HTTP Rest calls. It is similar to JdbcTemplate and JmsTemplate where these abstractions encapsulate lower level calls what can be performed with a library like apache http components.

Project set up

[0:48]

We will set up a project with spring boot and utilize the test class created.

Making a first request

[0:31]

SparkFun is a neat product that allows people to push data to a public free location for consumption. So if you are looking for data or want the ability to store data via REST calls, this might be an option. We found a data stream called Wimp Weather Station that provides weather readings from on top of somebody's roof in Colorado. Let's make a request to the URI and view the response as a String.

Creating a new class RestTemplate we will call getForEntity passing in a URL and the class we would like the response to be returned as.

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.getForEntity(
        "https://data.sparkfun.com/streams/dZ4EVmE8yGCRGx5XRX1W.json",
        String.class);

System.out.println(response);

Output

For sake of space, section of the nodes were omitted.

{
  "success":true,
  "publicKey":"dZ4EVmE8yGCRGx5XRX1W",
  "stream":{
    "_doc":{
      "tags":[
        "battery",
        "humidity",
        "light",
        "pressure",
        "rain",
        "temperature",
        "weather",
        "wind"
      ]
      "date":"2014-04-05T14:37:39.441Z",
      "last_push":"2014-09-12T18:22:26.252Z",
      "hidden":false,
      "flagged":false,
      "alias":"wimp_weather",
      "location":{
        "long":"Boulder, CO, United States",
        "city":"Boulder",
        "state":"Colorado",
        "country":"United States",
        "lat":"40.0149856",
        "lng":"-105.27054559999999"
      },
      "title":"Wimp Weather Station",
      "description":"Weather station on top my roof. Read the full tutorial here: https://learn.sparkfun.com/tutorials/weather-station-wirelessly-connected-to-wunderground",
      "__v":0,
      "_id":"534015331ebf49e11af8059d"
    },
  }
}

Converting request to java object

[1:12]

We specified a JSON string but that doesn't do us much good, we want to convert the JSON string to a java object.

Create wrapper objects

What we need to do is unwrap the json into multiple java objects which is tedious. We will create a condensed view of objects and fields for the request by first creating a SparkResponseWrapper, SparkStreamWrapper, DocWrapper and WimpWeatherLocationWrapper. You will notice in each wrapper object we included @JsonIgnoreProperties(ignoreUnknown = true) which is an indicator to jackson to fail if an unknown property is found in the deserialization process.

Update the Entity Class Type

We next replace String.class with SparkResponseWrapper.class where jackson will know to walk the json tree populating the java objects.

@Test
public void convert_json_response_to_java_obj() {

    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<SparkResponseWrapper> response = restTemplate
            .getForEntity(
                    "https://data.sparkfun.com/streams/dZ4EVmE8yGCRGx5XRX1W.json",
                    SparkResponseWrapper.class);

    System.out.println(response.getBody().getStream().getDocWrapper()
            .getLocation());
}

Output

WimpWeatherLocationWrapper [longValue=Boulder, CO, United States, city=Boulder, state=Colorado, country=United States, lat=40.0149856, lng=-105.27054559999999]

Handling an exception

[1:49]

In the event that your service call fails or the marshaling of the json to the java object throws an exception you may want to log the error or retry the request. If you aren't familiar, the http response deliver a status codes which indicate whether a specific request has been successfully completed. Luckily ResponseEntity adds the status code just for this reason.

We will reference a status code enum constant and check the status code returned in the response.

@Test
public void test_successful_response() {

    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<String> response = restTemplate.getForEntity(
            "https://data.sparkfun.com/streams/dZ4EVmE8yGCRGx5XRX1W.json",
            String.class);
    
    if (HttpStatus.OK == response.getStatusCode()) {
        System.out.println(response);
    } else {
        // log error, retry or ? 
    }
}

RestTemplate with proxy

If you receive a connection timed out exception, like the one below, it is quite possible that you are sitting behind a proxy. If so, you will need to take additional steps to configure RestTemplate by using a SimpleClientHttpRequestFactory, an implementation of ClientHttpRequestFactory, and passing in a Proxy object. The snippet below should give you a reference.

org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://data.sparkfun.com/streams/dZ4EVmE8yGCRGx5XRX1W.json":Connection timed out: connect; nested exception is java.net.ConnectException: Connection timed out: connect
...
Caused by: java.net.ConnectException: Connection timed out: connect
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:370)
SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("my.proxy.com", 9999));
clientHttpRequestFactory.setProxy(proxy);

RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
ResponseEntity<String> response = restTemplate.getForEntity(
        "https://data.sparkfun.com/streams/dZ4EVmE8yGCRGx5XRX1W.json",
        String.class);

Be aware

[2:17]

This screen cast is a high level simple configuration and just scratches the surface on how to make a http rest request in java. Other items to investigate is making calls with request methods (GET, POST, PUT, etc), configuring a proxy, dealing with SSL certificates, connection pooling, configuring timeouts on the request and the list goes on. As you are making this tutorial and implementing a solution be aware that this is just the tip of the iceberg so be sure to reach out to your web infrastructure teams.

Hope you enjoyed today's level up, have a great day!