Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

restTemplate delete with body

I am trying to do DELETE with request body but I keep getting 400 (bad request) error. When I do it in the swagger/postman, it is successfully deleting the record. But from the Java code I can't do that

The external API is designed in a way that it needs body along with URL. It can't be changed. please let me know how can I delete that entry with request body

public Person delete(Person person, String url, Map<String, String> uriVariables) throws JsonProcessingException {
        RestTemplate restTemplate = new RestTemplate();
        CustomObjectMapper mapper = new CustomObjectMapper();
        HttpEntity<Person> requestEntity = new HttpEntity<Person>(person);
        try {
            ResponseEntity<Person> responseEntity = restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, Person.class, uriVariables);
            return responseEntity.getBody();
        } catch (RestClientException e) {
            System.out.println(mapper.writeValueAsString(person));
            throw e;
        }
    }

when it goes to exception, I will get the JSON request in JSON format and the same works fine in Swagger/postman

I did some googling and found that restTemplate have problem deleting when there is request body. this article wasn't helpful https://jira.spring.io/browse/SPR-12361 is there any way to get it work

like image 995
Shiva Avatar asked Apr 27 '16 19:04

Shiva


People also ask

What is difference between getForObject and getForEntity?

For example, the method getForObject() will perform a GET and return an object. getForEntity() : executes a GET request and returns an object of ResponseEntity class that contains both the status code and the resource as an object. getForObject() : similar to getForEntity() , but returns the resource directly.

Why RestTemplate is deprecated?

RestTemplate provides a synchronous way of consuming Rest services, which means it will block the thread until it receives a response. RestTemplate is deprecated since Spring 5 which means it's not really that future proof. First, we create a Spring Boot project with the spring-boot-starter-web dependency.

What does RestTemplate getForEntity do?

getForEntity. Retrieve an entity by doing a GET on the specified URL. The response is converted and stored in an ResponseEntity . URI Template variables are expanded using the given URI variables, if any.

What is the RestTemplate Exchange () method for?

To put it simply, the set of exchange functions are the most general/capable methods provided by RestTemplate , so you can use exchange when none of the other methods provides a complete enough parameter set to meet your needs.


2 Answers

Another way to fix this is to use restTemplate.exchange, here's an example:

try {
      String jsonPayload  = GSON.toJson(request);
      HttpEntity<String> entity = new HttpEntity<String>(jsonPayload.toString(),headers());
      ResponseEntity resp = restTemplate.exchange(url, HttpMethod.DELETE, entity, String.class);
} catch (HttpClientErrorException e) {
      /* Handle error */
}

The nice thing about this solution is that you can use it with all HttpMethod types.

like image 158
Jim Holland Avatar answered Sep 28 '22 01:09

Jim Holland


Issue exists for Spring version 4.0.x or earlier.
In later version it has been fixed.

This might be a late answer, but in one of my project I solved this issue via a custom ClientHttpRequestFactory to RestTemplate

If no factory is provided to RestTemplate, it uses default implementation SimpleClientHttpRequestFactory

In SimpleClientHttpRequestFactory class, DELETE method is not allowed with request body.

if ("PUT".equals(httpMethod) || "POST".equals(httpMethod) ||     
         "PATCH".equals(httpMethod)) {
    connection.setDoOutput(true);
}
else {
    connection.setDoOutput(false);
}

Just write your own implementation as

import java.io.IOException;
import java.net.HttpURLConnection;

import org.springframework.http.client.SimpleClientHttpRequestFactory;

public class CustomClientHttpRequestFactory extends SimpleClientHttpRequestFactory {

    @Override
    protected void prepareConnection(HttpURLConnection connection, 
            String httpMethod) throws IOException {

        super.prepareConnection(connection, httpMethod);
        if("DELETE".equals(httpMethod)) {
            connection.setDoOutput(true);
        }
    }
}

After that create your RestTemplate object as

RestTemplate template = new RestTemplate(
                            new CustomClientHttpRequestFactory());

Fix in later versions of (4.1.x or above) SimpleClientHttpRequestFactory class

if ("POST".equals(httpMethod) || "PUT".equals(httpMethod) ||
            "PATCH".equals(httpMethod) || "DELETE".equals(httpMethod)) {
    connection.setDoOutput(true);
}
else {
    connection.setDoOutput(false);
}
like image 27
Pratapi Hemant Patel Avatar answered Sep 28 '22 00:09

Pratapi Hemant Patel