Reputation: 321
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
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
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
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
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
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
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
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