rest icon indicating copy to clipboard operation
rest copied to clipboard

Add portable Http Client Engine interface

Open hantsy opened this issue 1 year ago • 17 comments

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);

hantsy avatar Aug 31 '24 03:08 hantsy

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?

mkarg avatar Aug 31 '24 09:08 mkarg

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 avatar Sep 02 '24 01:09 hantsy

@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?

jansupol avatar Sep 02 '24 19:09 jansupol

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.

This imposes strong restrictions on how a JAX-RS implementation is actually designed -- something that an API shall never do.

mkarg avatar Sep 02 '24 20:09 mkarg

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 avatar Sep 03 '24 02:09 hantsy

@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 ClientHttpRequestFactory used to build a RestClient(Blocking API), https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/client/ClientHttpRequestFactory.html
  • The ClientHttpConnector used to build a WebClient(Reactive API), https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/client/reactive/ClientHttpConnector.html

hantsy avatar Sep 03 '24 02:09 hantsy

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.

mkarg avatar Sep 04 '24 18:09 mkarg

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.

mkarg avatar Sep 04 '24 18:09 mkarg

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.

jamezp avatar Sep 11 '24 23:09 jamezp

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?

hantsy avatar Sep 12 '24 06:09 hantsy

FWIW RESTEasy does this with an SPI already, so it would work for RESTEasy.

If possible to port this to the public Rest specification?

hantsy avatar Sep 12 '24 06:09 hantsy

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?

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.

mkarg avatar Sep 13 '24 16:09 mkarg

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 avatar Dec 18 '24 01:12 hantsy

@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 avatar Dec 18 '24 01:12 jamezp

@jamezp But it seems this should be a consideration of the spec providers, not the spec.

hantsy avatar Dec 18 '24 01:12 hantsy

@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.

jamezp avatar Dec 18 '24 02:12 jamezp

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.

hantsy avatar Jan 15 '25 07:01 hantsy