Spring Rest template works out of the box when the response is JSON. It’s opinionated and easy. The trouble begins if you want to extract a response that is not JSON. In this case, the deep dive in knowing about message converters can make one dizzy.
In the opinionated case, to consume post to an API endpoint and consume the response can be as simple as
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(webhookURL);
URI ApiUrl = new URI(builder.buildAndExpand(urlParams).toUri().toString());
ResponseEntity<Object> objectResponseEntity = integrationAppRestClient.postForEntity(ApiUrl, payloadObject, Object.class);
Object body = objectResponseEntity.getBody();
return objectResponseEntity.getStatusCodeValue();
The above is Build API Url -> Post Response – > get status
But if the verbose non-opinionated – say if you want to consume a html response – will be
Charset utf8 = Charset.forName("UTF-8");
MediaType mediaType = new MediaType("text", "html", utf8);
headers.setContentType(mediaType);
HttpEntity<Object> httpEntity = new HttpEntity<>(postResponse, headers);
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(webhookURL);
ApiUrl = new URI(builder.buildAndExpand(urlParams).toUri().toString());
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_HTML));
integrationAppRestClient.getMessageConverters().add(converter);
ResponseEntity<String> objectResponseEntity = integrationAppRestClient.exchange(ApiUrl, HttpMethod.POST, httpEntity, String.class);
return objectResponseEntity.getStatusCodeValue();
Set the headers -> Create an HttpEntity as you are now going to add (headers, payload) together as an entity -> set the converters that will consume the html response -> make sure the final respone can consume the HTML as string so set String as return type
So that’s the overhead.
In the spring-web HttpMessageConverterExtractor class, here is where most of the magic takes place and most of the exceptions that “there was no suitable converter found for response” will originate from.
public T extractData(ClientHttpResponse response) throws IOException {
MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response);
if (responseWrapper.hasMessageBody() && !responseWrapper.hasEmptyMessageBody()) {
MediaType contentType = this.getContentType(responseWrapper);
try {
Iterator var4 = this.messageConverters.iterator();
while(var4.hasNext()) {
HttpMessageConverter<?> messageConverter = (HttpMessageConverter)var4.next();
if (messageConverter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter<?> genericMessageConverter = (GenericHttpMessageConverter)messageConverter;
if (genericMessageConverter.canRead(this.responseType, (Class)null, contentType)) {
if (this.logger.isDebugEnabled()) {
ResolvableType resolvableType = ResolvableType.forType(this.responseType);
this.logger.debug("Reading to [" + resolvableType + "]");
}
return genericMessageConverter.read(this.responseType, (Class)null, responseWrapper);
}
}
if (this.responseClass != null && messageConverter.canRead(this.responseClass, contentType)) {
if (this.logger.isDebugEnabled()) {
String className = this.responseClass.getName();
this.logger.debug("Reading to [" + className + "] as \"" + contentType + "\"");
}
return messageConverter.read(this.responseClass, responseWrapper);
}
}
} catch (HttpMessageNotReadableException | IOException var8) {
throw new RestClientException("Error while extracting response for type [" + this.responseType + "] and content type [" + contentType + "]", var8);
}
throw new RestClientException("Could not extract response: no suitable HttpMessageConverter found for response type [" + this.responseType + "] and content type [" + contentType + "]");
} else {
return null;
}
}