Building a Reusable RestTemplate Utility for Clean HTTP Requests in Spring Boot

1. RestTemplate Bean Configuration

The basic configuration creates a RestTemplate instance as a Spring bean:

@Configuration
public class RestTemplateConfiguration {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

For environments using self-signed certificates (such as development or testing), you can configure RestTemplate to skip SSL verification:

@Bean
public RestTemplate restTemplate() throws Exception {
    SSLContext sslContext = SSLContextBuilder.create()
            .loadTrustMaterial(new TrustSelfSignedStrategy())
            .build();

    CloseableHttpClient httpClient = HttpClients.custom()
            .setSSLContext(sslContext)
            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
            .build();

    HttpComponentsClientHttpRequestFactory requestFactory = 
            new HttpComponentsClientHttpRequestFactory(httpClient);

    return new RestTemplate(requestFactory);
}

2. HTTP Utility Class Implementation

Creating a dedicated utility component centralizes HTTP handling logic, improves code reusability, and provides consistent exception handling across your application.

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

/**
 * HTTP request utility component
 */
@Component
public class HttpClientHelper {
    private static final Logger log = LoggerFactory.getLogger(HttpClientHelper.class);
    
    @Autowired
    private RestTemplate httpClient;

    /**
     * Execute GET request with custom headers
     */
    public String executeGet(String endpoint, Map<String, String> requestHeaders) {
        HttpHeaders headers = new HttpHeaders();
        if (requestHeaders != null) {
            requestHeaders.forEach(headers::add);
        }
        HttpEntity<String> request = new HttpEntity<>(headers);
        
        try {
            ResponseEntity<String> response = httpClient.exchange(
                    endpoint, HttpMethod.GET, request, String.class);
            return response.getBody();
        } catch (HttpStatusCodeException ex) {
            log.error("GET request failed with status {} to {}: {}", 
                    ex.getStatusCode(), endpoint, ex.getResponseBodyAsString());
            throw ex;
        } catch (RestClientException ex) {
            log.error("Connection error during GET request to {}: {}", 
                    endpoint, ex.getMessage());
            throw ex;
        }
    }

    /**
     * Execute POST request with JSON body
     */
    public String executePost(String endpoint, Map<String, Object> payload, 
                              Map<String, String> requestHeaders) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json;charset=UTF-8");
        if (requestHeaders != null) {
            requestHeaders.forEach(headers::add);
        }
        
        String jsonBody = convertToJson(payload);
        HttpEntity<String> request = new HttpEntity<>(jsonBody, headers);
        
        try {
            ResponseEntity<String> response = httpClient.exchange(
                    endpoint, HttpMethod.POST, request, String.class);
            return response.getBody();
        } catch (HttpStatusCodeException ex) {
            log.error("POST request failed with status {} to {}: {}", 
                    ex.getStatusCode(), endpoint, ex.getResponseBodyAsString());
            throw ex;
        } catch (RestClientException ex) {
            log.error("Connection error during POST request to {}: {}", 
                    endpoint, ex.getMessage());
            throw ex;
        }
    }

    private static String convertToJson(Map<String, Object> data) {
        return JSON.toJSONString(data);
    }
}

3. Service Integration Example

Inject the utility into your service layer for clean, readable API calls:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class ExternalApiService {

    @Autowired
    private HttpClientHelper httpHelper;

    public void callExternalEndpoints() {
        String fetchEndpoint = "https://api.example.com/resource";
        String submitEndpoint = "https://api.example.com/submit";
        
        Map<String, Object> payload = new HashMap<>();
        payload.put("username", "admin");
        payload.put("age", 25);

        // GET request example
        String fetchResult = httpHelper.executeGet(fetchEndpoint, null);
        System.out.println("GET Result: " + fetchResult);

        // POST request example
        Map<String, String> authHeaders = new HashMap<>();
        authHeaders.put("Authorization", "Bearer token123");
        String submitResult = httpHelper.executePost(submitEndpoint, payload, authHeaders);
        System.out.println("POST Result: " + submitResult);
    }
}

4. Frequently Asked Questions

  • Is RestTemplate thread-safe? Yes, RestTemplate instances are thread-safe when used as singletons. Inject a single bean instance across your application.
  • How to handle HTTPS certificate errors? Configure NoopHostnameVerifier and TrustSelfSignedStrategy in the SSL context (shown in section 1). Only use this in non-production environmetns.
  • How to add PUT and DELETE support? Extend the utility class with similar methods using HttpMethod.PUT and HttpMethod.DELETE flolowing the same pattern.

Tags: spring-boot RestTemplate http-client java spring-framework

Posted on Sat, 06 Jun 2026 17:27:51 +0000 by ArizonaJohn