I am trying to convert a curl request, which is giving me a token into Spring's Resttemplate post request, but I am getting 403 - bad request
My Curl Request
curl -d "grant_type=client_credentials&client_id=nu5yzeth9tektzf5egxuntp7&client_secret=uP2Xvr6SCKYgXgxxJsv2QkUG"
-H "Content-Type: application/x-www-form-urlencoded"
-X POST https://cloudsso.example.com/as/token.oauth2
Curl Response:
{"access_token":"HVURQ845OPJqs8UpOlef5m2ZCNwR","token_type":"Bearer","expires_in":3599}
Now, Here is my Java code to implement above curl post request
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
MultiValueMap<String, String> bodyParamMap = new LinkedMultiValueMap<String, String>();
bodyParamMap.add("grant_type", "client_credentials");
bodyParamMap.add("client_id", "nu5yzeth9tektzf5egxuntp7");
bodyParamMap.add("client_secret", "uP2Xvr6SCKYgXgxxJsv2QkUG");
entity = new HttpEntity<>(reqBodyData, bodyParamMap);
restTemplate.postForEntity(url, entity, TokenDTO.class)
Resttemplate call response:
2019-12-04 11:10:16,483[0;39m [39mDEBUG[0;39m [[34mrestartedMain[0;39m] [33morg.springframework.core.log.CompositeLog[0;39m: Accept=[application/json, application/*+json]
[30m2019-12-04 11:10:16,484[0;39m [39mDEBUG[0;39m [[34mrestartedMain[0;39m] [33morg.springframework.core.log.CompositeLog[0;39m: Writing [{"grant_type":["client_credentials"],"client_id":["nu5yzeth9tektzf5egxuntp7"],"client_secret":["uP2Xvr6SCKYgXgxxJsv2QkUG"]}] with org.springframework.http.converter.StringHttpMessageConverter
[30m2019-12-04 11:10:17,976[0;39m [39mDEBUG[0;39m [[34mrestartedMain[0;39m] [33morg.springframework.core.log.CompositeLog[0;39m: Response 400 BAD_REQUEST
[30m2019-12-04 11:10:17,981[0;39m [34mINFO [0;39m [[34mrestartedMain[0;39m] [33mcom.ibm.ciscoApiIntegration.service.impl.CiscoAPIServiceImpl[0;39m: e::: 400 Bad Request
How can make the above curl request in RestTemplate working?
Note: https://cloudsso.example.com/as/token.oauth2 it's little modified for the question.
If you take a look at the documentation for HttpEntity you will see that you are using the wrong constructor.
entity = new HttpEntity<>(reqBodyData, bodyParamMap);
You are passing the arguments you want to use as the body (bodyParamMap) as headers (as the second argument is the headers to be used for the request). In fact you aren't even using the HttpHeaders for the request as you aren't passing them to the HttpEntity. I'm not sure what the reqBodyData is but probably a toString of the bodyParamMap.
What you should have been doing is the following
entity = new HttpEntity<>(bodyParamMap, headers);
As HttpHeaders impements MultiValueMap you can directly use them in the constructor. You also want to pass the bodyParamMap as is.
NOTE: I would also suggest to explictly set the Content-Type on the HttpHeaders so you are sure what is being send.
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
Thus the total resulting code should look like
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> bodyParamMap = new LinkedMultiValueMap<>();
bodyParamMap.add("grant_type", "client_credentials");
bodyParamMap.add("client_id", "nu5yzeth9tektzf5egxuntp7");
bodyParamMap.add("client_secret", "uP2Xvr6SCKYgXgxxJsv2QkUG");
entity = new HttpEntity<>(bodyParamMap, headers);
restTemplate.postForEntity(url, entity, TokenDTO.class)
NOTE: You shouldn't be constructing a single use RestTemplate but you rather want to configure that once and inject that into your class.
I have just solved the issue:
I had this in this
// wrong
//private HttpEntity<String> entity;
I changed it to this:
private MultiValueMap<String, String> parametersMap;
and changed it
// not working
entity = new HttpEntity<>(reqBodyData, bodyParamMap);
to this
// working
entity = new HttpEntity<>(bodyParamMap, headers);
Now it's working perfectly fine.
response:
2019-12-04 11:52:46,503 DEBUG [restartedMain] org.springframework.core.log.CompositeLog: HTTP POST https://cloudsso.example.com/as/token.oauth2
2019-12-04 11:52:46,521 DEBUG [restartedMain] org.springframework.core.log.CompositeLog: Accept=[application/json, application/*+json]
2019-12-04 11:52:46,522 DEBUG [restartedMain] org.springframework.core.log.CompositeLog: Writing [{grant_type=[client_credentials], client_id=[nu5yzeth9tektzf5egxuntp7], client_secret=[uP2Xvr6SCKYgXgxxJsv2QkUG]}] with org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
2019-12-04 11:52:47,831 DEBUG [restartedMain] org.springframework.core.log.CompositeLog: Response 200 OK
Note: in my case, adding or disabling this value, isn't making any difference, i am getting the auth token anyway.
//headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
As suggested by post https://stackoverflow.com/a/49127760/11226302
You should set the request content type in header as;
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
Hope this helps!
Related
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?
I have a url generated by a GET method which is somewhat of this format:
https://service-name/api?param1=<value1>¶m2=<value2>¶m3=<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);
Hi I am able to call a rest api through postman . I have added the following in body part of postman. client_id - xxxx , client_secret - *** etc.
Now i want to make rest api call through java. How do i add these body parameters to request being created from java
If you are using Spring, you can use the RestTemplate Spring REST client to make a call to an external API from Java.
Example:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> request = new HttpEntity<>(someDto, headers)
restTemplate.postForEntity(postUrl, request, String.class);
Reading the API of Github, it demands a custom headers : "vnd.github.antiope-preview+json"; Using spring boot.
I always get 415 Unsupported Media Type eventhough that's what's mentioned in the github API page.
HttpHeaders headers = new headers.setAccept(Collections.singletonList(new MediaType("application","vnd.github.antiope-preview+json")));
headers.setContentType();
HttpEntity<String> entity = new HttpEntity<>(str,headers);
restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
For information , I did it on postman with the same headers.
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).