rest
rest copied to clipboard
Add portable Http Client Engine interface
Currently, we(the end developers) do not know which the rest clients use which HTTP Client library in the background, like the issue I mentioned in https://github.com/jakartaee/rest/issues/1276, we need to add more provider-specific properties to use it.
I would like use a more fine-grained configuration on the background HttpClient itself directly.
Expose a HttpConnector interface to allow developers to customize it as expected.
ClientBuilder.httpConnector(
custom JdkHttpClientHttpConnector
or ApacheHttpClientHttpConnector
or JettyClientHttpConnector
or NettyClientHttpConnector
etc...
)
For example, JdkHttpClientHttpConnector can be instantize simply as the following.
new JdkHttpClientHttpConnector(); // create a built-in JDK 11 HttpClient internally.
Or accept a your custom JDK 11 HttpClient.
var executorService = Executors.newFixedThreadPool(5);
var httpClient = HttpClient.newBuilder()
.executor(executorService)
.version(HttpClient.Version.HTTP_2)
.build();
new JdkHttpClientHttpConnector(httpClient);
What shall vendors do that currently are JAX-RS compatible, but that do not have replaceable backends, but just one hardcoded backend? Shall they not be JAX-RS compatible anymore or do you pay their costs for reworking their kernel to support replaceable backends?
Having said that, wouldn't it be enough to mandata that IF a vendor supports replaceable backends, then they MUST support predefined properties to configure them?
I hope the spec provider can provide their HttpConnector implementations freely, but at least give an implementation based on JDK 11 HttpClient, and make it the default implementation(for the end users, we do not need to add more dependencies).
The end user can also implement its own HttpConnector impl to replace the one in the provider. For example, in one project, we use OkHttp as an HTTP client to handle all client cases, but this Jaxrs provider does not provide an OKHttp version, to align with our codes and we do not want to introduce new dependencies, we can impl a HttpConnector based on OkHttp.
@hantsy Can you try to prototype some way to hook in the connector? It is not clear to me what simply new JdkHttpClientHttpConnector(httpClient); would do to deliver the response. Do you mean some static approach or some other way?
I hope the spec provider can provide their
HttpConnectorimplementations freely, but at least give an implementation based on JDK 11 HttpClient, and make it the default implementation(for the end users, we do not need to add more dependencies).The end user can also implement its own HttpConnector impl to replace the one in the provider. For example, in one project, we use OkHttp as an HTTP client to handle all client cases, but this Jaxrs provider does not provide an OKHttp version, to align with our codes and we do not want to introduce new dependencies, we can impl a HttpConnector based on OkHttp.
This imposes strong restrictions on how a JAX-RS implementation is actually designed -- something that an API shall never do.
something that an API shall never do. Like the Jakarta Rest spec, there are several impls, such as Eclipse Jersey, Resteasy etc.
It is not just an API, in the end user's mind, it is a framework, that should be provide more flexible options.
@hantsy Can you try to prototype some way to hook in the connector? It is not clear to me what
simply new JdkHttpClientHttpConnector(httpClient);would do to deliver the response. Do you mean some static approach or some other way?
The new Spring 6.x provides a RestClient, and Spring also provided a WebClient since 5.x. Unlike the former client tools(eg. restTemplate), they offer a configurable option to switch the background HTTP Client engine and allow developers to configure HTTP Message codecs details.
Check the following docs for more details.
- The
ClientHttpRequestFactoryused to build aRestClient(Blocking API), https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/client/ClientHttpRequestFactory.html - The
ClientHttpConnectorused to build aWebClient(Reactive API), https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/client/reactive/ClientHttpConnector.html
It is not just an API, in the end user's mind, it is a framework, that should be provide more flexible options.
Jakarta REST is not a framework, it is just an API.
I think if we adopt this idea, then there should be a separate Jakarta subprojekt for defining such an API that we can build upon.
One thing to point out is the JDK HTTP Client doesn't implement everything needed to work with the jakara.ws.rs.client.Client. For example, the Jakarta REST Client allows the a hostname verifier to be set which you cannot do on the JDK's HTTP Client. I proposed we deprecate that, but it's a breaking change and was rejected.
FWIW RESTEasy does this with an SPI already, so it would work for RESTEasy.
That said, I don't think the Jakarta REST API should provide any implementations, nor should they be required to even implement one. I can see this useful to an end user where they might want to use some custom HTTP client.
I think if we adopt this idea, then there should be a separate Jakarta subprojekt for defining such an API that we can build upon.
I do not think so.
Jakarta Rest Client itself can use switchable serialization/deserialization providers, filters, portable rx invokers, etc., so why the HTTP client should be a subproject?
FWIW RESTEasy does this with an SPI already, so it would work for RESTEasy.
If possible to port this to the public Rest specification?
I think if we adopt this idea, then there should be a separate Jakarta subprojekt for defining such an API that we can build upon.
I do not think so.
Jakarta Rest
Clientitself can use switchable serialization/deserialization providers, filters, portable rx invokers, etc., so why the HTTP client should be a subproject?
Because it makes sense to have the same interface whereever pure HTTP services are needed. Jakarta REST is just a REST API, not a generic HTTP client. What we need here is not a REST-only API, but a pure HTTP API. It makes sense that other projects (even non-Jakarta-projects) make use of this. In fact, it should be defined by the vendors of these HTTP Clients, not the the consuming REST engines.
For example, the Jakarta REST Client allows the a hostname verifier to be set which you cannot do on the JDK's HTTP Client. I https://github.com/jakartaee/rest/issues/1161 we deprecate that, but it's a breaking change and was rejected.
@jamezp Can we use/create a standalone host verifier to replace the classic httpurlconnection one?
@hantsy Not to my knowledge. The HostnameVerifier can only be enabled or disabled via a system property on the java.net.http.HttpClient, see https://bugs.openjdk.org/browse/JDK-8213309. Potentially you could create some kind of custom SSLContext, but you'd had to likely re-implement a bunch of things.
@jamezp But it seems this should be a consideration of the spec providers, not the spec.
@hantsy Correct and has a spec provider, I definitely don't want to implement that :) It's been a while since I looked at it, but it was heavily integrated into the java.net.http.HttpClient. It might even be impossible to override it in the HttpClient.
Like the RxInvoker to accept async results and reactive results, I hope the HttpClientEngine is also exchangeable, as a developer we accept some breaking changes when a big version update.