RestTemplate gives 400 Bad Request Error on a Get Request - spring

When I try to make a get request with Spring's RestTemplate, it gives 400 BAD Request. I can call the same url from javascript successfully with the headers below :
But the code below does not work. What might be the cause?
public Entity getEntityByUri(String uri) {
String req = "http://live.dbpedia.org/sparql?query=DESCRIBE%20%3Chttp://dbpedia.org/resource/Concept_learning%3E&format=application%2Fjson-ld";
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.ALL));
HttpEntity<String> httpEntity = new HttpEntity<String>(headers);
new RestTemplate().exchange(req, HttpMethod.GET, httpEntity, Map.class);
Entity entity = new Entity();
return entity;
}

Your url is already encoded. Popular browsers such as Chrome are capable of understanding and responding appropriately. However, it's not the same case with RestTemplate.
I had to decode your uri here and the decoded uri is DESCRIBE <http://dbpedia.org/resource/Concept_learning>
Having checked the browser console, I got to know you have two query strings passed in the url, they are query and format holding values DESCRIBE <http://dbpedia.org/resource/Concept_learning> and application/json-ld respectively.
I assume Entity class is the pojo class of json response.
Have created Entity as from your json response:
public class Entity {
private String value;
private String type;
// getters and setters omitted for brevity
}
Finally in your getEntityByUri method have got the instance of UriComponentsBuilder which handles uri encoding and query params.
To sum up, your getEntityByUri looks below.
public HttpEntity<Entity> getEntityByUri() {
String req = "http://live.dbpedia.org/sparql";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(req)
.queryParam("query",
"DESCRIBE <http://dbpedia.org/resource/Concept_learning>")
.queryParam("format", "application/json-ld");
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.ALL));
HttpEntity<String> httpEntity = new HttpEntity<String>(headers);
return new RestTemplate().exchange(builder.build().encode().toUri(), HttpMethod.GET, httpEntity, Entity.class);
}
The above method didn't throw HTTP400 as the required query params have been passed in builder object.
Hope this helps and good luck!

Anyone getting same error make sure your URL is decoded means no percent symbols in url (if space in param values).
This worked for me
try {
requestURL = URLDecoder.decode("http://api.com?p=1&groups=3212&affected-since=2019-06-06T14%3A11%3A14.880&detail=full&after-id=43536", "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

Maybe
headers.setAccept(Arrays.asList(MediaType.ALL));
generates a malformed "Accept" header field? (FWIW, why do you send it at all???)

Related

spring boot rest client connection Exception:: org.springframework.web.client.HttpClientErrorException: 400 null

while i am executing below code i am getting error like
"org.springframework.web.client.HttpClientErrorException: 400 null".
but when i use postman to call this "http://localhost:2018/test" it is working.
static final String URL_EMPLOYEES = "http://localhost:2018/test";
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(new MediaType[] {
MediaType.APPLICATION_JSON}));
// Request to return XML format
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("replyMsg", "str");
// HttpEntity<Employee[]>: To get result as Employee[].
HttpEntity<String> entity = new HttpEntity<String>(headers);
// RestTemplate
RestTemplate restTemplate = new RestTemplate();
// Send request with GET method, and Headers.
ResponseEntity<String> response =
restTemplate.exchange(URL_EMPLOYEES,
HttpMethod.POST, entity,String.class);
HttpStatus statusCode = response.getStatusCode();
// Status Code: 200
if (statusCode == HttpStatus.OK) {
// Response Body Data
msg=response.getBody();
if (msg != null) {
System.out.println(msg);
}
}
//my clint controller class
#RestController
public class TextController {
#RequestMapping(value="/test",method = RequestMethod.POST)
public String myData2(#RequestBody String payload) {
return "done";
}
}
any suggetions?
If you're using Jackson as your JSON parser, you can simply declare your parameter with the type TextNode. This is the Jackson type representing JSON strings.
public String updateName(#PathVariable(MY_ID) String myId, #RequestBody TextNode name) {
You can then use its asText method to retrieve its text value.
Here you are setting headers Content-Type with type JSON and passing the body of type text/String.
headers.setContentType(MediaType.APPLICATION_JSON); //setting your Content type as JSON.
So, First you need to change this to
headers.setContentType(MediaType.TEXT_PLAIN); //setting your Content type as Pure Text String.
and add some code after this line
// HttpEntity<Employee[]>: To get result as Employee[].
HttpEntity<String> entity = new HttpEntity<String>(headers);
add this code
// HttpEntity<Employee[]>: To get result as Employee[].
HttpEntity<String> entity = new HttpEntity<String>(headers);
// RestTemplate
RestTemplate restTemplate = new RestTemplate();
// Send request with GET method, and Headers.
String entity_Str = new ObjectMapper().writeValueAsString(entity);
ResponseEntity<String> response =
restTemplate.exchange(URL_EMPLOYEES,
HttpMethod.POST, entity_Str, String.class);
This might work for you.. Thanks :)

Spring RestTemplate receives "401 Unauthorized"

I am using the following to retrieve JSON via RestTemplate in Spring 4:
protected DocInfoResponse retrieveData(String urlWithAuth) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + auth.getSig());
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<DocInfoResponse> response = restTemplate.exchange(urlWithAuth, HttpMethod.GET, request, DocInfoResponse.class);
return response.getBody();
}
I used the same code (with different response class) to successfully get a JSON doc from the same site (with different parameters to get a different doc).
When I execute the above code I receive the following stack trace (in part):
Caused by: org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
at
org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
Can anyone point me to why this might be receiving the exception?
I found that my issue originally posted above was due to double encryption happening on the auth params. I resolved it by using UriComponentsBuilder and explicitly calling encode() on the the exchange().
SyncResponse retrieveData(UriComponentsBuilder builder) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<SyncResponse> response = restTemplate.exchange(builder.build().encode().toUri(), HttpMethod.GET, request, SyncResponse.class);
return response.getBody();
}
My UriComponentsBuilder was built using:
UriComponentsBuilder buildUrl(String urlString) {
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(urlString);
return auth.appendAuth(builder);
}
(The auth.appendAuth() adds additional .queryParams() needed by the target service in urlString.)
The call to execute this was retrieveData(buildUrl(urlString));.
After investigating on my own problem, I realized that FireFox RESTClient was successful because I was connected to the target URL. The Basic Auth I thought I was using, was not so basic after all.
Eventually, I read the doc of the app i was trying to connect to and realized they propose a connection token mechanism. Now it works.
After reading your code, I say it looks quite OK, although I'm not sure what is your object auth on which you call getSig.
First things first: try to access your service from any client, like a web browser, a PostMan or RESTClient. Make sure you successfully retrieve your infos WITHOUT being connected to your app!!!
Depending on the result, I say you should, either try to encrypt manually your Authorization token (you'll easilly find posts on this site to show you how to) or try another connection mechanism.
The process of creating the Authorization header is relatively straightforward for Basic Authentication, so it can pretty much be done manually with a few lines of code:
HttpHeaders createHeaders(String username, String password){
return new HttpHeaders() {{
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(
auth.getBytes(Charset.forName("US-ASCII")) );
String authHeader = "Basic " + new String( encodedAuth );
set( "Authorization", authHeader );
}};
}
Then, sending a request becomes just as simple:
RestTemplate restTemplate = new RestTemplate();
restTemplate.exchange
(uri, HttpMethod.POST, new HttpEntity<T>(createHeaders(username, password)), clazz);
https://www.baeldung.com/how-to-use-resttemplate-with-basic-authentication-in-spring#manual_auth

RestTemplate POST request urlformencoded gives 400 (Bad Request)

I have the following request :
String url = "url to oauth_token";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
RestTemplate restTemplate = new RestTemplate();
String body = "grant_type=authorization_code&client_id=123&client_secret=123&"
+ "redirect_uri=https://axyz.com&code=123";
HttpEntity<Object> entity = new HttpEntity<>(body, headers);
Object token = restTemplate.exchange(url, HttpMethod.POST, entity, Object.class);
This seems to return 400 (Bad Request). I have also tried its alternatives where body is a MultiValueMap but this is what makes the most sense to me. Is there something wrong with the way I am trying the request?
The values of the POST fields should be URL encoded (you can use URLEncoder.encode(value, "UTF-8") for each value while concatenating the body string). That's why you get 400 error.
You'd better use a more convenient way to create a POST form entity with keys and values, which will URL encode your values automatically:
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("param1", "value1"));
formparams.add(new BasicNameValuePair("redirect_uri", "https://axyz.com"));
...
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);

How to send GET request with headers by Spring

It will call another REST API with a GET request.
#RequestMapping(value = "xxxx/{id}", method = RequestMethod.GET)
public #ResponseBody GetObjet GET( #PathVariable("id") String id,
#RequestHeader(value="X-Auth-Token") String Token) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("X-Auth-Token", Token);
HttpEntity entity = new HttpEntity(headers);
ResponseEntity<GetObjet> response = restTemplate.exchange(url, HttpMethod.GET, entity, GetObjet.class);
return response.getBody();
}
Always 400 Error. It means that bad request or some errors in the request body. But this is GET so the resquest bodys is always empty. So this way to add header may be not right. Any ideas?
You can obtain the headers including the notation #RequestHeader in your method
public void displayHeaderInfo(#RequestHeader("Accept-Encoding") String encoding,
#RequestHeader("Keep-Alive") long keepAlive) {
}
o
You can read more about the request here
And the other way to abtain the URL is:
#RequestMapping(value = "/restURL")
public String serveRest(#RequestBody String body, #RequestHeader HttpHeaders headers){
//Use headers to get the information about all the request headers
long contentLength = headers.getContentLength();
...
StreamSource source = new StreamSource(new StringReader(body));
YourObject obj = (YourObject) jaxb2Mashaller.unmarshal(source);
...
}
Try using:
RestTemplate.getForEntity(url, GetObject.class);
You have some methods to request data from a rest API, such as getForEntity and getForObject, use the one you needed.

Spring Rest Template to send JsonArray

I am using spring rest template to send json array as request. Source code to send request is as follow:
JSONArray jsonArray = new JSONArray();
for (Iterator iterator = itemlist.iterator(); iterator.hasNext();) {
Item item = (Item)iterator.next();
JSONObject formDetailsJson = new JSONObject();
formDetailsJson.put("id", item.getItemConfId());
formDetailsJson.put("name", item.getItems().getItemName());
formDetailsJson.put("price", item.getPrice());
formDetailsJson.put("Cost",item.getCost());
jsonArray.put(formDetailsJson);
}
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
// Prepare header
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
// Pass the new person and header
HttpEntity<JSONArray> entity = new HttpEntity<JSONArray>(jsonArray, headers);
System.out.println("Json Object : "+entity);
// Send the request as POST
try {
ResponseEntity<String> result = restTemplate.exchange("my url", HttpMethod.POST, entity, String.class);
} catch (Exception e) {
logger.error(e);
return "Connection not avilable please try again";
}
And to accept request:
#RequestMapping(value = "/testStock", method = RequestMethod.POST,headers="Accept=application/xml, application/json")
public #ResponseBody int testStock(#RequestBody List<ItemList> jsonArray) {
logger.debug("Received request to connect ms access : "+jsonArray.size());
//int returnSizecount = stockList.getStocklst().size();
return 1;
}
The problem is that it giving me following error:
Could not write request: no suitable HttpMessageConverter found for request type [org.json.JSONArray].Any suggestion is greatly acceptable.
There are no MessageConverter for JSONArray, so I suggest do the following.
HttpEntity<JSONArray> entity = new HttpEntity<JSONArray>(jsonArray, headers);
Convert Class JSONArray to String, and add that to HttpEntity, you know use toString
java.lang.String toString()
Make a JSON text of this JSONArray.
HttpEntity entity = new HttpEntity(jsonArray.toString(), headers);
Or change to Jackson implementation Spring have support to that. XD
If you dont want to do the above, consider create your own implementation of messageConverter, that will work but is harder
update
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
headers.setContentType(MediaType.APPLICATION_JSON);
update 2 Change endpoint to.
#RequestMapping(value = "/testStock", method = RequestMethod.POST)
public #ResponseBody int testStock(#RequestBody String jsonArray) {
you need to have httpmessageconverter configured for your resttemplate, please read my post for configuring http message conveter for you webservice
http://stackoverflow.com/questions/19963127/new-to-spring-and-jackson-2-what-does-this-bean-declaration-allow-for-in-a-spri/19973636#19973636.
and for you problem to convert your http request to json you might add this entry in your restemplate configuration
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
The error is quite straightforward. You do not have a converter for the JSONArray. Converting the array to a String (using toString) did help you here, but there is a better way:
Just add a converter for the json.org objects:
Add this to your pom.xml
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-json-org</artifactId>
</dependency>
And then on your ObjectMapper add the JsonOrgModule:
mapper.registerModule(new JsonOrgModule());

Resources