RestTemplate not working with APPLICATION_FORM_URLENCODED and Request Pojo - java

I am using restTemplate to consume a service.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity request = new HttpEntity(countryRequest, headers);
CountryResponse response = restTemplate.postForObject(countryURL, request, CountryResponse.class);
countryRequest is a object of a POJO with just a string field code.
restTemplate has jackson2HttpMessageConverter and FormHttpMessageConverter in messageConverters.
I am getting the following exception :
org.springframework.web.client.RestClientException:
Could not write request: no suitable HttpMessageConverter found for request type [CountryRequest] and content type [application/x-www-form-urlencoded]
But if I use MultiValueMap instead of CountryRequest, I got the 200 response:
MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
map.add(code, "usa");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity(map, headers);
Is there any way to replace the MultiValueMap approach here?

There is two main kinds of request serialization: as usual FORM data or as JSON object.
Form Data is simplest and oldest way which sends a simple key-value pairs of strings in POST payload. But when you need to send some object with nested properties or some list or even map then it becomes a problem.
That's why everybody tries to use a JSON format which can be more easily deserialized into POJO object. And this is a de facto standard for modern web.
So in your case for some reason RestTemplate tries to serialize the CountryRequest but it don't know how to serialize it into FORM data.
Try to replace the request with a pojo that you are sending:
CountryRequest request = new CountryRequest();
CountryResponse response = restTemplate.postForObject(countryURL, request, CountryResponse.class);
Then RestTemplate tries to serialize the CountryRequest into JSON (which is default behavior).

Related

Calling multiple external APIs in Spring Boot

I am working on a project but it requires me to call multiple external APIs. I basically have to call an API to get a player id by giving a name. Then use that player id to get a list of match ids. Then make calls for each match id to get details on each match. its alot and doesnt seem optimal but its the only way to do it. I was going to use rest template to make a call to the following
https://americas.api.riotgames.com/lol/match/v5/matches/by-puuid/HDzjdaStxhHcceGGd8qJcc4Vw45FOlOQ1PNXKQ0h9_iqfwHP3oI0spl1bLUOw_7_J49vzaIKylv5Vg/ids?start=0&count=20
I have to pass in headers as well such as
riot token : token
"Origin": "https://developer.riotgames.com"
I was wondering how I can do this in Java Spring boot. I saw RestTemplate would be used but I couldnt figure out how to include the headers. Any guidance would be appreciated.
You can call RestTemplate.exchange() using either the method signature with RequestEntity or with HttpEntity.
// Using RequestEntity
RequestEntity<?> request= RequestEntity.get(url).header(headerName, headerValue).build();
ResponseEntity<String> response = restTemplate.exchange(request, String.class);
// Using HttpEntity
HttpHeaders headers = new HttpHeaders();
headers.set(headerName, headerValue);
HttpEntity httpEntity = new HttpEntity(/* this is nullable */ requestBody, headers);
ResponseEntity,String> response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
Would also recommend reading through the following:
https://howtodoinjava.com/spring-boot2/resttemplate/spring-restful-client-resttemplate-example/
https://www.baeldung.com/rest-template
How to set an "Accept:" header on Spring RestTemplate request?

Spring Boot - How to send a POST request via a url with query parameters and store the response inside a method?

I have a url generated by a GET method which is somewhat of this format:
https://service-name/api?param1=<value1>&param2=<value2>&param3=<value3>.....
I need to hit this url and store the response (which will be of type application/x-www-form-urlencoded) into a variable, which will be used further.
The issue is that it needs to be done inside the method (get the url and pass it to get a response).
How to go about it?
For a spring boot application to consume an external API, you can use RestTemplate.
An example of usage is below. The response you receive is of type String.
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.add("Header", "header1");
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("https://foo/api/v3/projects/1/labels")
.queryParam("param1", param1)
.queryParam("param2", param2);
HttpEntity<?> entity = new HttpEntity<>(headers);
HttpEntity<String> response = restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
entity,
String.class);

Passing Request Body to Spring Rest Template without using LinkedMultiValueMap

I'm using the Spring Rest Template to make an Http PUT request and up until now I have been passing the request body using the following:
MultiValueMap<String, Object> body = new LinkedMultiValueMap<String, Object>();
body.add("account", testAccount);
HttpEntity<?> requestEntity = new HttpEntity<Object>(body, headers);
ResponseEntity<String> responseEntity;
try {
responseEntity = rest.exchange(uri, HttpMethod.PUT, requestEntity, String.class);
}
catch (HttpStatusCodeException e) {
log.error("Http PUT failed with response: " + e.getStatusText());
return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsString());
}
return responseEntity;
The request body that gets sent to my target API appears as:
{"account":[{"account_id":"495"}]}
This works, but my target API is not expecting the account object to have an array as a value and is currently giving me a 500 Internal Server Error, so, my question is, how can I get the value of the 'account' property to be an object rather than an array? For example I would like the request body to appear as:
{"account":{"account_id":"495"}}
Is there another type of Map which can be used which does not accept multiple values?
I would still like to use the exchange method if possible.
Any on help on this would be grand! Many thanks
The answer was actually simply using a regular HashMap instead of the MultiValueMap. As seen here the MultiValueMapcase is used when you want to add an array to a single key in the request body.
Thanks for all the help.

Handle multipart/mixed response with Spring RestTemplate

I'm making a rest call to an endpoint that returns a multipart/mixed payload.
Here's the call using Spring's RestTemplate:
ResponseEntity<String> res = template.exchange(queryStr, HttpMethod.GET, entity, String.class);
I know I can get the entire body from the ResponseEntity as a String, but I don't want to have to manually parse it. Isn't there a more elegant way to handle the parsing of multipart/mixed. I've tried things like:
ResponseEntity<MultipartFile> res = template.exchange(queryStr, HttpMethod.GET, entity, MultipartFile.class);
but I get this exception:
org.springframework.web.client.RestClientException Could not extract response: no suitable HttpMessageConverter found for response type [interface org.springframework.web.multipart.MultipartFile] and content type [multipart/mixed;boundary=ML_BOUNDARY_10842596526049964806]
Thoughts?

How to properly setup a POST spring rest template by passing in parameters and return json?

I am a bit new to spring and I am having issues calling a rest service using post to a ur in spring by using spring templates
I am not sure how to properly pass in data into the rest template and how to get json data out currently i get 415 unsupport media type error.
So the RestservicesURL.signupurl = "abc.com/signup
the param would be = "name=john?email=john#doe.com?password=john" (which is acquired by #RequestParam Map by spring)
The response I need to get is a JSON object and I am not sure how to do this;
public void signUp(Map<String, String> param) {
try {
callService(RestServicesUrl.SIGNUP_URL, param);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Here is the rest template call
public static void callService(String url, Map<String, String> data) throws Exception {
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.ALL);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
HttpEntity<String> entity = new HttpEntity<String>(headers);
RestTemplate rest = new RestTemplate();
rest.postForObject(url, entity, byte[].class);
}
Are you trying to post JSON as well as receive it?
Based on your "data" variable it looks like you might be trying to send JSON. I see you have "ALL" set on the acceptable media types, if you're posting JSON and expect to receive it back, you should put the acceptable media type and Content-Type headers to "application/json". I believe Spring has constants for these. This could be the cause of your 415 unsupported mediatype error.
As for creating your JSON, you should strongly consider a serialization framework to convert your Java objects into JSON for you and vice versa - Jackson is a very popular option and is tied closely into Spring's functionality for this, see details here: RestTemplate + Jackson
If that's not an option, you'll need to figure out a way to get your data object converted into the appropriate HTTP request with an HTTPMessageConverter.

Categories

Resources