RestTemplate Explained.
RestTemplate is a synchronous client to perform HTTP requests.
RestTemplate Bean RestTemplate is best decalred as a java bean for reusability.
Create RestTemplate bean and RestTemplate bean with connection timeout
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Configuration public class RestTemplateConfig { @Bean @Primary public RestTemplate restTemplate () { return new RestTemplate (); } @Bean("restTemplateWithTimeout") public RestTemplate restTemplateWithTimeout () { int timeout = 5000 ; HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory (); clientHttpRequestFactory.setConnectTimeout(timeout); return new RestTemplate (clientHttpRequestFactory); } }
RestTemplate Demo Methods
getForObject
getForEntity()
postForEntity()
exchange()
If you need to set the HTTP request headers, you need to use exchange
method.
MyService.java - Here are the methods inside a service(MyService) that uses RestTemplate to call jsonplaceholder API endpoint.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 public Post simpleGet () { log.info("------------RestTemplate.getForEntity()-----------" ); try { ResponseEntity<Post> response = restTemplate.getForEntity( "https://jsonplaceholder.typicode.com/posts/1" , Post.class); if (response.getStatusCode() == HttpStatus.OK) { log.info("Response body: " + response.getBody()); return response.getBody(); } } catch (RestClientException e ) { log.error("Fail to retrieve Post" , e); throw e; } return null ; } public Post[] exchangeWithUriVariables() { log.info("------------RestTemplate.getForEntity() getting Array -----------" ); try { Map<String,String> uriVariables = new HashMap <>(); uriVariables.put("key1" , "value1" ); uriVariables.put("key2" , "value2" ); HttpHeaders headers = new HttpHeaders (); headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); HttpEntity<Void> requestEntity = new HttpEntity <>(headers); ResponseEntity<Post[]> response = restTemplate.exchange( "https://jsonplaceholder.typicode.com/posts" , HttpMethod.GET, requestEntity, Post[].class, uriVariables ); if (response.getStatusCode() == HttpStatus.OK) { log.info("Response body size: " + response.getBody().length); return response.getBody(); } } catch (RestClientException e ) { log.error("Fail to retrieve Post array" , e); throw e; } return null ; } public Post simplePost () { log.info("------------RestTemplate.postForEntity()-----------" ); try { Post post = new Post (); post.setTitle("Test" ); post.setBody("some content" ); post.setId(333 ); post.setUserId(234 ); HttpEntity<Post> requestEntity = new HttpEntity <>(post); ResponseEntity<Post> response = restTemplate.postForEntity( "https://jsonplaceholder.typicode.com/posts" , requestEntity, Post.class); if (response.getStatusCode() == HttpStatus.CREATED) { log.info("Response body: " + response.getBody()); return response.getBody(); } } catch (RestClientException e ) { log.error("Fail to post post" , e); throw e; } return null ; } public Post exchangePost () { log.info("------------RestTemplate.exchange() POST-----------" ); try { Post post = new Post (); post.setTitle("Test" ); post.setBody("some content" ); post.setId(333 ); post.setUserId(234 ); HttpHeaders headers = new HttpHeaders (); headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); HttpEntity<Post> requestEntity = new HttpEntity <>(post, headers); ResponseEntity<Post> response = restTemplate.exchange( "https://jsonplaceholder.typicode.com/posts" , HttpMethod.POST, requestEntity, Post.class); if (response.getStatusCode() == HttpStatus.CREATED) { log.info("Response body: " + response.getBody()); return response.getBody(); } } catch (RestClientException e ) { log.error("Fail to retrieve post" , e); throw e; } return null ; } public Post exchangePut () { log.info("------------RestTemplate.exchange() PUT-----------" ); try { Post post = new Post (); post.setTitle("Test" ); post.setBody("some content" ); post.setId(333 ); post.setUserId(234 ); HttpEntity<Post> requestEntity = new HttpEntity <>(post); ResponseEntity<Post> response = restTemplate.exchange( "https://jsonplaceholder.typicode.com/posts/1" , HttpMethod.PUT, requestEntity, Post.class); if (response.getStatusCode() == HttpStatus.OK) { log.info("Response body: " + response.getBody()); return response.getBody(); } } catch (RestClientException e ) { log.error("Fail to put Post" , e); throw e; } return null ; } public void simpleDelete () { log.info("------------RestTemplate.delete()-----------" ); try { restTemplate.delete("https://jsonplaceholder.typicode.com/posts/1" ); log.info("delete successfully" ); } catch (RestClientException e) { log.error("Fail to delete post" , e); throw e; } }
Interceptor Spring RestTemplate allows us to add interceptors that implement ClientHttpRequestInterceptor interface. The intercept(HttpRequest, byte[], ClientHttpRequestExecution)
method of this interface will intercept the given request and return the response by giving us access to the request, body and execution objects.
Define a RestTemplate Interceptor that logs request headers, request body and response headers
1 2 3 4 5 6 7 8 9 10 11 12 13 @Component public class RestClientLogInterceptor implements ClientHttpRequestInterceptor { private static final Logger LOG = LoggerFactory.getLogger(RestClientLogInterceptor.class); @Override public ClientHttpResponse intercept (HttpRequest request, byte [] body, ClientHttpRequestExecution execution) throws IOException { request.getHeaders().forEach((k,v) -> LOG.debug("Request Header[{}]: {}" , k, v)); LOG.debug("Request body: {}" , new String (reqBody)); ClientHttpResponse response = execution.execute(request, body); response.getHeaders().forEach((k,v) -> LOG.debug("Response Header[{}]: {}" , k, v)); return response; } }
create RestTemplate bean with Interceptor
1 2 3 4 5 6 @Bean("restTemplateWithInterceptor") public RestTemplate restTemplateWithInterceptor () { RestTemplate restTemplate = new RestTemplate (); restTemplate.setInterceptors(Collections.singletonList(new RestClientLogInterceptor ())); return restTemplate; }
Testing RestTemplate Here is some test cases that tests the service class with RestTemplate service calls.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class MyServiceTest { private static RestTemplate restTemplate; private static MyService myService; @BeforeEach public void init () { restTemplate = mock(RestTemplate.class); myService = new MyService (restTemplate); } @Test public void testSimpleGet () { Post responseBody = new Post (); responseBody.setId(1 ); responseBody.setTitle("Post Title" ); responseBody.setBody("Some Content" ); ResponseEntity<Post> response = ResponseEntity.ok(responseBody); when(restTemplate.getForEntity( anyString(), eq(Post.class))).thenReturn(response); Post post = myService.simpleGet(); assertEquals(1 , post.getId()); assertEquals("Post Title" , post.getTitle()); } @Test public void testExchangePost () { Post responseBody = new Post (); responseBody.setId(1 ); responseBody.setTitle("Post Title" ); responseBody.setBody("Some Content" ); ResponseEntity<Post> response = ResponseEntity.status(HttpStatus.CREATED).body(responseBody); when(restTemplate.exchange( anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Post.class))).thenReturn(response); Post post = myService.exchangePost(); assertEquals(1 , post.getId()); assertEquals("Post Title" , post.getTitle()); ArgumentCaptor<HttpEntity> argCaptor = ArgumentCaptor.forClass(HttpEntity.class); verify(restTemplate).exchange( anyString(), eq(HttpMethod.POST), argCaptor.capture(), eq(Post.class)); Post reqBody = (Post) argCaptor.getValue().getBody(); assertEquals("Test" , reqBody.getTitle()); assertTrue(argCaptor.getValue().getHeaders().getAccept().stream() .anyMatch( type -> type.toString().equals(MediaType.APPLICATION_JSON_VALUE.toString()))); } }
WebClient RestTemplate is synchronous. It will be deprecated in the future version. WebClient is an modern webclient that can perform sync and async requests. see https://www.baeldung.com/spring-5-webclient for more details.
Link to Source Code: https://github.com/xinghua24/SpringBootExamples/tree/master/RestTemplateExample
Reference