Aug 16, 2016

Enhancements to Spring RestTemplate

Recently I had to choose a client to make REST requests from a Grails 2.5 application. I decided to give the Spring RestTemplate a try. It has worked very well, but was missing some functionality that most other clients provide. First off, most clients allow you to set a base URL. This is nice since usually you have a service that builds and configures the client for you. The second was the ability to use Basic Auth. The final piece was to allow for URL parameters to be automatically added to a get request. Thankfully the additional pieces of functionality were easy to add. I have shown what was needed below along with some examples.

Setup

The custom rest template that extends RestTemplate and allows for a base path and the automatic addition of url parameters.

import org.springframework.web.client.RequestCallback
import org.springframework.web.client.ResponseExtractor
import org.springframework.web.client.RestClientException
import org.springframework.web.client.RestTemplate
import org.springframework.web.util.UriComponentsBuilder
import org.springframework.web.util.UriTemplate
 
class CustomRestTemplate extends RestTemplate {
    String baseUrl
 
    //allow for the use of a base url
    @Override
    protected  T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor responseExtractor) throws RestClientException {
        return super.doExecute(new URI(baseUrl + url.toString()), method, requestCallback, responseExtractor)
    }
 
    //handle the url expansion our self and if any of the url variables are not in the url add them as a query parameter
    @Override
    public  T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor responseExtractor, Map urlVariables) throws RestClientException {
        URI expanded = new UriTemplate(url).expand(urlVariables)
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(expanded)
 
        urlVariables.each { key, value ->
            if(!url.contains("{$key}")) {
                if(value instanceof List) {
                    value.each {
                        uriComponentsBuilder.queryParam(key, it)
                    }
                } else {
                    uriComponentsBuilder.queryParam(key, value)
                }
            }
        }
 
        return super.execute(uriComponentsBuilder.toUriString(), method, requestCallback, responseExtractor)
    }
}

The interceptor that allows for basic auth.

import org.apache.commons.codec.binary.Base64
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpRequest
import org.springframework.http.client.ClientHttpRequestExecution
import org.springframework.http.client.ClientHttpRequestInterceptor
import org.springframework.http.client.ClientHttpResponse
 
public class BasicAuthInterceptor implements ClientHttpRequestInterceptor {
    private final String username
    private final String password
 
    public BasicAuthInterceptor(String username, String password) {
        this.username = username
        this.password = password
    }
 
    //If the basic auth credentials are missing add them to the request header
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution ) throws IOException {
        HttpHeaders httpHeaders = request.getHeaders()
        if(!httpHeaders.containsKey(HttpHeaders.AUTHORIZATION)) {
            byte[] userPasswordBytes = (username + ":" + password).bytes
            String basicAuth = "Basic " + new String(Base64.encodeBase64(userPasswordBytes))
            httpHeaders.set(HttpHeaders.AUTHORIZATION, basicAuth)
        }
 
        return execution.execute(request, body)
    }
}

Examples

An example service that builds our rest template and adds the basic auth interceptor.

import org.springframework.web.client.RestTemplate
 
class ExampleService {
	static transactional = false
	def grailsApplication
 
	//returns a rest template that has its base url and basic auth credentials configured
	RestTemplate getRestTemplate() {
		//Create a rest template with the base url set from a grails config property
		def baseUrl = grailsApplication.config.client.api.baseUrl
		def template = new CustomRestTemplate(baseUrl: baseUrl)
 
		//add basic auth credentials to the template with an interceptor
		def username = grailsApplication.config.client.api.username
		def password = grailsApplication.config.client.api.password
		def basicAuthInterceptor = new BasicAuthInterceptor(username, password)
		template.interceptors = [basicAuthInterceptor]
 
		return template
	}
}

The following example now makes a request to http://base-url/object?sort=attribute&order=desc&offset=10&max=10 with the basic auth header included. Notice has the params are just added to the URL.

def restTemplate = exampleService.getRestTemplate()
def params = [sort: "attribute", order: "desc", offset: 10, max: 100]
def jsonObject = restTemplate.getForObject("/object", JSONObject, params)

While this example makes a request to http://base-url/object/1?detail=full with the basic auth header included. This shows we can combine the two methods and use the Spring parameter replacement method, {id}, also.

params = [id: 1, detail: "full"]
jsonObject = restTemplate.getForObject("/object/{id}", JSONObject, params)

About the Author

Paul Ferguson profile.

Paul Ferguson

Sr. Consultant

An Insightful, results-driven software engineer with over 23 years of experience working for small startups to Fortune 500 companies. I excel at developing solutions to meet ever-changing business requirements within diverse industries. I am a self motivated, quick learning developer who loves the collaboration and problem solving each day brings as a consultant. I have spent most of my career in the server side Java world. Recently I have been focused on micro services with event streaming using Spring Boot, Go and the Kafka ecosystem. Even though the core of my experience has been server side I started as a full stack developer and try to keep up. This is becoming increasingly difficult, yet important as front end technologies have transitioned from being mostly visual to now integral parts of an applications functionality.

While out of the office Paul enjoys working on projects around the house, cooking, trying out new foods and beers as well as cheering for the Vikings, Wild and Twins.

One thought on “Enhancements to Spring RestTemplate

  1. Søren Berg Glasius says:

    Great example. You could even do your configuration in resources.groovy:

    beans = {
    restInterceptor(BasicAuthInterceptor) {
    username = application.config.client.api.username
    password = application.config.client.api.password
    }

    restTemplate(CustomRestTemplate) {
    baseUrl = application.config.client.api.baseUrl
    interceptors= [ref(‘restInterceptor’)]
    }

    restBuilder(RestBuilder) {
    restTemplate = ref(‘restTemplate’)
    }
    }

    then you can inject the restBuilder bean where you need to do rest-calls.

    1. Thank You. While you certainly could I personally only like to have injected beans only come from services in Grails. I feel it adds extra complexity if you add them in resources.grooy or by another method, because then you have to hunt down how the bean was created.

  2. H F says:

    Why do you do this instead of using DefaultUriTemplateHandler to set the base URL on your RestTemplate?

    I’m less certain that this is equivalent but why not use BasicAuthorizationInterceptor?

    1. It is great to see that Spring has addressed these issues in their newer versions. Spring 4.2 adds DefaultUriTemplateHandler and 4.3.1 adds BasicAuthorizationInterceptor. Unfortunately for me I am working with a Grails app that is the latest 2 version, 2.5.5 at this time. For those wondering what version of Grails you need to use these features Grails 3.2.2 uses Spring 4.3.1 and Grails 3.1 uses Spring 4.2.

Leave a Reply to Paul Ferguson Cancel reply

Your email address will not be published.

Related Blog Posts
Natively Compiled Java on Google App Engine
Google App Engine is a platform-as-a-service product that is marketed as a way to get your applications into the cloud without necessarily knowing all of the infrastructure bits and pieces to do so. Google App […]
Building Better Data Visualization Experiences: Part 2 of 2
If you don't have a Ph.D. in data science, the raw data might be difficult to comprehend. This is where data visualization comes in.
Unleashing Feature Flags onto Kafka Consumers
Feature flags are a tool to strategically enable or disable functionality at runtime. They are often used to drive different user experiences but can also be useful in real-time data systems. In this post, we’ll […]
A security model for developers
Software security is more important than ever, but developing secure applications is more confusing than ever. TLS, mTLS, RBAC, SAML, OAUTH, OWASP, GDPR, SASL, RSA, JWT, cookie, attack vector, DDoS, firewall, VPN, security groups, exploit, […]