LitterWalker
LitterWalker

Reputation: 321

How do I implement a PATCH executed via RestTemplate?

I am coding JUnit tests, calling my application via RestTemplate. I have successfully implemented GETs, POSTs, and PUTs, but can not get a PATCH to run (though it works when a client sends in the URL). A POST, for example, runs with this code:

    RestTemplate restTemplate = new RestTemplate(); 
    ProductModel postModel = restTemplate.postForObject(TestBase.URL + URL, pModel, ProductModel.class);            

But when I tried to call restTemplate.patchForObject() - which I found online - STS returns an error saying that function is not defined. I thus used this:

    RestTemplate restTemplate = new RestTemplate(); 
    ResponseEntity<MessageModel> retval = restTemplate.exchange("http://localhost:8080/products/batchUpdateProductPositions", 
            HttpMethod.PATCH, new HttpEntity<ProductPositionListModel>(pps), MessageModel.class);   

Which compiles, but gives me an error:

I/O Error on PATCH request for "http://localhost:8080/products/batchUpdateProductPositions": Invalid HTTP method: PATCH

In the application, I have the operation defined in a Controller class:

@RequestMapping(value = "/batchUpdateProductPositions", method = RequestMethod.PATCH)
public MessageModel batchUpdatePosition(
        @RequestBody ProductPositionListModel productPositionList)
        throws Exception {
    try {
        return productService.batchUpdatePosition(productPositionList);
    } catch (Exception e) {

I put a breakpoint on the return statement inside the 'try' block, but it never tripped when I ran it under debug.

Can anyone tell me where I tripped up?

Upvotes: 5

Views: 17948

Answers (7)

Theri Muthu Selvam
Theri Muthu Selvam

Reputation: 162

Use the following code to overcome this issue,

Add the below dependency in pom.xml,

<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    </dependency>
<dependency>

Import CloseableHttpClient, and HttpClients from the above dependency's jar file.

To make HTTP Patch request using RestTemplate, below configurations are mandatory, for other HTTP calls you may ignore it.

import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;

@Bean
public RestTemplate restTemplate() {
    LOGGER.info("restTemplate Bean has bean created");
    CloseableHttpClient httpClient = HttpClients.createDefault();
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
    RestTemplate restTemplate = new RestTemplate(factory);
    return restTemplate;
}

In the request class use the below code,

ResponseEntity<Object> response = restTemplate.exchange(url, HttpMethod.PATCH,  requestEntity, Object.class);

Upvotes: 0

Priyantha
Priyantha

Reputation: 5093

WebClient offers a modern alternative to the RestTemplate with efficient support for both sync and async, as well as streaming scenarios. You can implement this with WebClient.

Configure WebClient

@Configuration
public class WebConfig {
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}

Then you can call method

//Constructor Injection 
public YourClassName(WebClient.Builder webClientBuilder) {
   this.webClientBuilder = webClientBuilder;
}

MessageModel response = webClientBuilder.build()
                .patch()
                .uri("http://localhost:8080/products/batchUpdateProductPositions")
                .contentType(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToMono(MessageModel.class)
                .block();

Dependency for pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
     

Upvotes: 0

Oluyide Olugbenga
Oluyide Olugbenga

Reputation: 11

Try this:

import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
//...
RestTemplate rest = new RestTemplate(new HttpComponentsClientHttpRequestFactory())

//Now make the PATCH call using Exchange
ResponseEntity<Map<String, Object>> response = rest.exchange(api, HttpMethod.PATCH, request, responseType);

Do not forget to add this to your dependencies:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.4.1</version>
 </dependency>

Upvotes: 1

Harendra Kr. Jadon
Harendra Kr. Jadon

Reputation: 179

This works for me, for execution of a PATCH request using RestTemplate:

RestTemplate restTemplate = new RestTemplate();

HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectTimeout(timeout);
httpRequestFactory.setReadTimeout(timeout);

restTemplate.setRequestFactory(httpRequestFactory);

Now use this restTemplate with exchange().

Required Dependency

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency> 

Upvotes: 2

Mayte Espi Hermida
Mayte Espi Hermida

Reputation: 21

This Solution

MessageModel pModel = restTemplate.postForObject(TestBase.URL + URL + "/batchUpdateProductPositions?_method=patch",pps, MessageModel.class);   

Is useful if you are using a Post Method(@PostMapping), If you would like to use Patch Method(@PatchMapping), Try this:

restTemplate.patchForObject("http://localhost:8080/products/batchUpdateProductPositions", requestEntity, String.class);

Upvotes: 0

LitterWalker
LitterWalker

Reputation: 321

I discovered a solution that stays consistent with the rest of the JUnit code. Using postForObject(), you can pass in the HTTP method you need in this case:

    MessageModel pModel = restTemplate.postForObject(TestBase.URL + URL + "/batchUpdateProductPositions?_method=patch", 
            pps, MessageModel.class);           

This runs correctly. Couldn't say if there are side effects I'm not noticing.

Upvotes: 2

Alexander Yanyshin
Alexander Yanyshin

Reputation: 1370

By default RestTemplate uses standard JDK HttpURLConnection HTTP client to make requests. This client does not support PATCH method. You can configure RestTemplate to use some other HTTP client via client factory, like HttpComponentsClientHttpRequestFactory or OkHttpClientHttpRequestFactory.

HttpClient client = HttpClients.createDefault();
RestTemplate template= new RestTemplate();
template.setRequestFactory(new HttpComponentsClientHttpRequestFactory(client)); 

You will also need to add proper dependencies, something like org.apache.httpcomponents:httpclient:$version in case HTTP Components client.

Upvotes: 8

Related Questions