curl ok, RestTemplate fails - spring

This works:
curl --verbose -H "Content-Type: application/json" --data "{\"parm1\":\"1\", \"parm2\":\"1\"}" http://server:8080/service/meth
and returns:
{"success":true,"errorMessage":null}
This fails:
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("parm1", "1");
map.add("parm2", "1");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
String response = (String) restTemplate.postForObject("http://server:8080/service/meth",
request,
String.class);
with 500 Internal Server Error
I'm using springframework-boot 1.3.3.RELEASE and java 1.8 and am at a loss as to what's wrong. The server side log shows no errors other than 500
Has anyone been faced with a Spring RestTemplate call that mysteriously failed? How did you approach diagnosing the problem?

Related

415 Error when authenticating - Spring boot and RestTemplate

I am working on a third-party REST API and I am going to authenticate with their API by making a POST request to the provided end point. I tested this end point using Postman and it works fine, and now I wanted to do it programmatically.
I am using Spring boot 3.0 for development and RestTemplate as the http client. The code I have implemented is below, it gives me a 415 UNSUPPORTED_MEDIA_TYPE error.
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==");
headers.add("Accept", "application/json");
headers.add("Content-Type","application/x-www-form-urlencoded");
MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<String, String>();
requestBody.add("grant_type", "client_credentials");
HttpEntity formEntity = new HttpEntity<MultiValueMap<String, String>>(requestBody, headers);
String serverEndPoint = "https://xxxxxxx.xxx/auth/oauth2/xx/token";
ResponseEntity<String> response = restTemplate.exchange(serverEndPoint, HttpMethod.POST,formEntity, String.class);
System.out.println(response.getStatusCode().value());
Build RestTemplate
#Bean
public RestTemplate getRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
// don't throw
}
});
return restTemplate;
}
But same logic I have implemented using Jersey http client as mentioned below, it gives me successful response with 200 response code.
JacksonJsonProvider jacksonJsonProvider = new JacksonJaxbJsonProvider()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Client client = ClientBuilder.newClient(new ClientConfig(jacksonJsonProvider));
Form form = new Form();
form.param("grant_type", "client_credentials");
String serverEndPoint = "https://xxxxxxx.xxx/auth/oauth2/xx/token";
Response response = client.target(serverEndPoint)
.request("application/json")
.header("Authorization", "Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==")
.post(Entity.entity(form, APPLICATION_FORM_URLENCODED));
System.out.println(response.getStatus());
Kindly help me to resolve this since I need to move forward with the RestTemplate client.
cUrl From Postman
curl --location --request POST 'https://xxxxxxxxxxxxx.xxx/auth/oauth2/xx/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==' \
--header 'Cookie: coolie data bla bla' \
--data-urlencode 'grant_type=client_credentials'
If I inspect what the successful calls (curl and the Jersey HttpClient) send to the server vs what RestTemplate.exchange() sends, the only significant difference is that RestTempate.exchange() appends the charset=utf-8 to the Content-Type header.
I suspect that the sever you are calling is too strict on Content-Type and throws a 415 if it does not match "application/x-www-form-urlencoded" exactly.
To prevent this you need to use RestTempate.postForObject() instead. Try changing your RestTemplate call code as follows:
String serverEndPoint = "https://httpbin.org/post";
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> entity = new HttpEntity<>("grant_type=client_credentials", headers);
String result = restTemplate.postForObject( serverEndPoint, entity, String.class);
The MediaType is org.springframework.http.MediaType.
Note that I call httpbin.org in the code fragment. I find it extremely useful in researching an issue like this.

How to add file as Form data in Http request in spring boot

I'm writing test cases to a controller in spring boot which takes MultipartFile as RequestParam. In the test case method I'm using TestRestTemplate.exchange() to send the request to the controller. I'm not sure how to make the Headers correctly so that I can send the request.
The Postman curl looks like this:
curl --location --request POST 'localhost:9091/response/upload'
--form 'file=#"/home/adityak/Downloads/ClientLog_NEW.txt"'
For file uploading to any service or endpoint
private String testExchange(File file) {
//add file
LinkedMultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("file", new FileSystemResource(file));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity =
new HttpEntity<>(params, headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(
"/upload-file",
HttpMethod.POST,
requestEntity,
String.class);
HttpStatus statusCode = responseEntity.getStatusCode();
if (statusCode == HttpStatus.ACCEPTED) {
result = responseEntity.getBody();
}
return result;
}

Spring Boot Upload file via PUT

I have a curl query:
curl -v -X PUT --upload-file "test.txt" http://remote_api_service/api/files
I have a Spring Boot application and my goal is to write a query that reflects the curl I posted above. How can I do that with RestTemplate or WebClient?
You need to create HttpEntity with header and body. Set the content-type header value to MediaType.MULTIPART_FORM_DATA.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", new FileSystemResource("test.txt"));
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
String serverUrl = "http://remote_api_service/api/files";
RestTemplate restTemplate = new RestTemplate();
restTemplate.put(serverUrl, requestEntity);

How to not escape form body characters in Spring RestTemplate when making a POST request?

I have following code where I am making a POST form request. The request body contains username and password. Password contains # characters, which is replaced by RestTemplate with %40 and I am getting "unauthorized" error as the password is wrong now.
Following is the debug info from bufferOutput(request body)
merchant_id=firstname+de-lastname%40gmail.com&password=%40Password
Here is the code snippet that is making the call.
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
String url = "SOME_URL";
formData.add("username", "xay#gmail.com");
formData.add("password", "#name321");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String,String>> requestEntity = new HttpEntity<MultiValueMap<String,String>>(formData,headers);
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters()
.add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
restTemplate.exchange(url, HttpMethod.POST, requestEntity, Authentication.class,"321");
The question is how to tell restTemplate not to escape body data ?
Note that the request has to be a post form request and I can not use UriComponentsBuilder to fix the problem.
I think you need to add a FormHttpMessageConverter to your RestTemplate rather than a StringHttpMessageConverter.

HTTP POST using JSON in Spring Rest

I would like to make a simple HTTP POST using Spring RestTemplate.
the Wesb service accept JSON in parameter for example: {"name":"mame","email":"email#gmail.com"}
public static void main(String[] args) {
final String uri = "url";
RestTemplate restTemplate = new RestTemplate();
// Add the Jackson message converter
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
// create request body
String input = "{ \"name\": \"name\", \"email\": \"email#gmail.com\" }";
JsonObject request = new JsonObject();
request.addProperty("model", input);
// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Basic " + "xxxxxxxxxxxx");
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);
// send request and parse result
ResponseEntity<String> response = restTemplate
.exchange(uri, HttpMethod.POST, entity, String.class);
System.out.println(response);
}
When I test this code I got this error:
Exception in thread "main" org.springframework.web.client.HttpClientErrorException: 400 Bad Request
when I call webservice with Curl I have correct result:
curl -X POST -H "Authorization: Basic xxxxxxxxxx" --header "Content-Type: application/json" --header "Accept: application/json" -d "{ \"name\": \"name\", \"email\": \"email#gmail.com\" } " "url"
try to remove model from the code, as i can see in your curl request you didn't use model attribute and everything works. try this:
public static void main(String[] args) {
final String uri = "url";
RestTemplate restTemplate = new RestTemplate();
// Add the Jackson message converter
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
// create request body
String input = "{\"name\":\"name\",\"email\":\"email#gmail.com\"}";
// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Basic " + "xxxxxxxxxxxx");
HttpEntity<String> entity = new HttpEntity<String>(input, headers);
// send request and parse result
ResponseEntity<String> response = restTemplate
.exchange(uri, HttpMethod.POST, entity, String.class);
System.out.println(response);
}

Resources