Peter Luttrell opened SPR-15347 and commented
The PATCH
HTTP method (rfc5789) is gaining popularity. In fact, Spring Data Rest Repositories provides endpoints that use it by default on all entities.
The RestTemplate
, however, does not support PATCH
out of the box because the RestTemplate
relies on SimpleClientHttpRequestFactory
, which in turn relies on the JDKs HttpURLConnection
class, which doesn't currently support it.
This issue has been reported elsewhere and treated as a documentation issue because if you choose other ways of making the connections...including several hacks..it will work. Reference #19618, GitHub Spring-cloud/spring-cloud-netflix issue #1777, GitHub Spring-cloud/spring-cloud-netflix issue #1022 and StackOverflow: RestTemplate PATCH request.
But treating this as a documentation issue doesn't serve the best interest of Spring users. Sure instructions for how to enable it is buried in the javadocs for Spring... but this introduces an unnecessary barrier to successfully using the RestTemplate with Spring Data Rest Repositories...or any other service that uses PATCH
calls. This could cause unnecessary frustration in using the RestTemplate
.
With this ticket, I propose that the RestTemplate
be enhanced to support the PATCH
method by default without any custom configuration.
This might also have the added benefit of better test coverage with whatever implementation is chosen.
Affects: 4.3.7
Issue Links: - #19618 Doc: Can't issue PATCH request using RestTemplate with SimpleClientHttpRequestFactory
Comment From: spring-projects-issues
Juergen Hoeller commented
So are you asking for HttpComponentsClientHttpRequestFactory
to be used by default there? We can't do anything about HttpURLConnection
's limitations in a given JDK, so the only alternative is to enforce a third-party library such as Apache HttpClient or OkHttp...
Comment From: spring-projects-issues
Peter Luttrell commented
I don't mean to specify or suggest how PATCH
is supported by default, just that it is supported by default.
Comment From: spring-projects-issues
Juergen Hoeller commented
A fair enough request :-)
Concretely though, since we're not going to reinvent an HTTP client library for that purpose, we'll have to consider enforcing Apache HttpClient or OkHttp by default. We could conditionally pick them up when present in the classpath... That would still require an explicit step in the application's setup though, choosing one of them in your set of runtime dependencies.
Comment From: spring-projects-issues
Brian Clozel commented
I truly understand the limitations and the frustration that comes with the default HTTP client implementation. RestTemplate
has no problem sending PATCH requests using underlying client libraries.
Several ways of solving this:
1. changing the defaults for Spring 5 and using a different client library; but for this to be effective, Spring Framework needs to ship with a mandatory dependency. I don't think it is wise to ship the spring-web module with a mandatory dependency on any http client library
2. having a flexible arrangement and detecting at runtime the client library of choice. This is what Spring Boot is doing. It's a quite opinionated territory and dealing with versions and advanced features by default is probably too opinionated for Framework.
3. use the new WebClient
which is only tied to modern client implementations (for now, only reactor-netty). AsyncRestTemplate
is already deprecated in favor of WebClient
, so this is very much in line with this policy.
Breaking the current RestTemplate
behavior or runtime requirements won't bring that much compared to using your own HTTP client of choice as a request factory, or the new WebClient
. So I'm closing this issue as "won't fix".
Thanks!
Comment From: vganesh
Hi,
No need to enforce Apache HttpClient or OkHttp by default or third party http client libraries from classpath. It works with JDK 11, the following code snippet was tested on my laptop using Windows.
Thx,
import java.io.IOException; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.ProxySelector; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpClient.Redirect; import java.net.http.HttpClient.Version; import java.net.http.HttpRequest; import java.net.http.HttpRequest.BodyPublisher; import java.net.http.HttpResponse; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException;
String proxyUrl='some_valid_url'; int proxyPort=8737;
private ResponseEntity<String> callPatchUsingHttpClient (String url, String body, String token) {
HttpClient client = HttpClient.newBuilder().version(Version.HTTP_1_1).followRedirects(Redirect.NORMAL) .connectTimeout(Duration.ofSeconds(20)) .proxy(ProxySelector.of(new InetSocketAddress(proxyUrl, proxyPort))).build();
BodyPublisher jsonPayload = HttpRequest.BodyPublishers.ofString(body);
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).method("PATCH", jsonPayload) .header("Content-Type", "application/json").header("Authorization", "Bearer " + token).build();
HttpResponse
}
Comment From: bclozel
Hello @vganesh
We don't have a RestTemplate connector for the JDK11 HTTP client so this code snippet doesn't apply to this issue. Thanks!