jsr339-experts@jax-rs-spec.java.net

[jsr339-experts] Re: client revisions

From: Marek Potociar <marek.potociar_at_oracle.com>
Date: Wed, 17 Aug 2011 17:33:09 +0200

Sorry for a delayed response. I have reviewed the proposed changes and based on the proposal bellow as well as based on
the feedback from Sergey, Guilherme and Markus I have the updated the proposed client API:

http://java.net/projects/jax-rs-spec/sources/git/show/src

The main changes include:

CORE HTTP REQUEST & RESPONSE API

- Introduced Headers, RequestHeaders and ResponseHeaders + inner Builder classes to hold the header-related APIs reused
in client-side fluent API as well as core HttpRequest and HttpResponse classes

- Introduced new core exception to decouple core req/resp classes from the client API

- Cleaned up and extended the HttpRequest/Response API ...somewhat :)

CLIENT BOOTSTRAPPING AND CONFIGURATION

- Added typed Feature support - see Feature and Configurable interfaces

- Removed redundant ClientConfiguration interface as well as DefaultClientConfiguration impl class

FLUENT CLIENT API

- Link renamed to Target
This is to distinguish the "active link" from the plain link header POJO (Link header POJO still to be introduced).

- Streamlined the fluent client API: client -> target -> invocation builder [ -> invocation] -> response
-- Invocation API was reduced to just support the command pattern for request processing
-- new Sync/AsyncInvoker interfaces were introuced to support HTTP method at the end of the fluent API method chain
-- Invocation.Builder was introduced to enforce the consistency in the fluent method invocation chain (e.g. the API does
not allow you to set a POST method and then invoke a GET). Such "advanced" features were removed from the fluent API,
but the flexibility for filters and handlers is retained since those work with mutable HttpRequest/Response interfaces.

Now, I know that with this fluent client API change we somewhat closed the loop with the client API proposals. The API
resembles the original proposal once again and the class hierarchy is more complex compared to the previous version.
Yet, this is not necessarily a bad thing IMHO. The problem with the older version of the API is that it was trying to do
too many things: it was supposed to be fluent, consistent and easy-to use, but also remain simple and lean (in terms of
class hierarchy) as well as super-flexible at the same time. The main point in providing a fluent API is however to be
primarily consistent and easy to use by the end users. Reduced flexibility and slightly increased complexity of the
class hierarchy is a reasonable price to pay. It is the usability of the fluent API that is important, not how the
javadoc looks like or how many (hidden) classes are there. And, again, please notice that the original flexibility
requirement is still preserved in the places where it makes most sense - filters and handlers are still using the
HttpRequest/Response interfaces.

With that, I am looking forward to your feedback,
Marek

On 07/05/2011 05:30 PM, Bill Burke wrote:
> I made some changes to client API to simplifiy it a little.
>
> https://github.com/patriot1burke/redhat-jaxrs-2.0-proposals-rev2
>
> * removed queue from Invocation interface
> * Added an AsyncInvocation interface
> * Added get/post/delete/etc. methods to AsyncInvocation and Invocation
> * removed invoke/queue methods from Client as they are redundant and I don't get why they are there.
> * removed HttpRequest.Builder as its not needed anymore
> * Link no longer extends HttpRequest.Builder
> * added request/async methods to Link
> * Gutted and simplified ClientFactory. No need for all those extra abstractions.
>
> You now are forced to put a get(), Post() or whatever at end of method call unless you are doing a custom HTTP method
> like PATCH. It now looks like:
>
> Client c = ...;
>
> Invocation invocation = c.request();
> HttpResponse response = invocation.header("foo", "bar").get();
> String str = invocation.header("foo", "bar").get(String.class);
>
> AsyncInvocation async = c.async();
> Future<HttpResponse> f = async.header("foo", "bar").get();
> Future<String> f = async.header("foo", "bar").get(String.class);
>
> Generic invocations are:
>
> Invocation invocation = c.request();
> HttpResponse response = invocation.header("foo", "bar").method("PATCH").invoke();
>
>
> Alternatively, you could combine Invocation/AsyncInvocation, but you'd have to rename get() to getAsync(), etc. I think
> originally it wasn't done this way because of the explosion of methods within Invocation.
>
>
>