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

[jsr339-experts] Re: Removing command pattern simplifies things

From: Marek Potociar <marek.potociar_at_oracle.com>
Date: Thu, 01 Sep 2011 14:13:34 +0200

On 08/31/2011 01:19 PM, Sergey Beryozkin wrote:
> Hi Marek
> On 31/08/11 12:08, Marek Potociar wrote:
>>
>>
>> On 08/31/2011 12:09 PM, Sergey Beryozkin wrote:
>>> I think it's good to try and model a nice and very clean process such as
>>> "Have a target URI created first", next go "Request" - set headers there, may be an entity and do a call, this is all
>>> sounds good.
>>> But I think it proves a bit too rigid/inflexible.
>>
>> That's how it is supposed to be. The fluent API should gently prod you in the direction of writing a well-formed HTTP
>> requests. If you need to write something that is not well-formed, you certainly can, but it may not look nice. And
>> that's actually a good thing.
>>
>> An if you really need a lot of extra flexibility, you can always use the Invocation API. It may be more verbose, but
>> that's the tax for the flexibility. You should not use that API if you really need only something simple anyway.
>>
> +1 to the above thoughts.
>
> IMHO the current version is inflexible. I don't understand how disallowing for an explicit CT setter or enforcing an
> entity wrapper, without having to resort to Invocation, and not being able to build a simple iteration logic, can
> protect a user from creating non-well formed requests.

IMHO, you did not do your homework and did not look at the examples at all. I have provided you some iteration examples
in a separate thread.

>
> Are you concerned about POSTs containg no CT ?

It's not just POSTs. I think that we should hint user that ANY request that contains entity SHOULD contain CT. That's
what th API does.

> I can kind of get that, but this is a low-level API, obviously users have to get some ideas of what formats are
> supported by the end receiver ? By adding this tight entity wrapper and not letting set a CT as is is not cool -
> likewise the fact I can't get back to resetting some bits of the current URI once I moved to a request stage is a big
> limitation IMHO

This is a low-level RESTful client API. Low-level HTTP client API is a lower layer and is going to be submitted as a
separate JSR sometime soon AFAIK.

Also, we are, again, running into the problem with your homework. It's simply not true that you cannot set CT without
sending entity. I don't see a use-case where it would make sense, but this is possible:

client.target(...).request().header("Content-Type", "text/plain").post(null);

It's not nice, but who cares. It's an ill-formed request, there's no reason why it should look nice. Btw. the fact that
the above is possible is a proof that the API *IS* low-level.

Marek

>
> Thanks, Sergey
>
>> Marek
>>
>>>
>>> Anyway, going to do some homework with the examples and provide more feedback :-)
>>>
>>> Sergey
>>>
>>> On 31/08/11 11:03, Sergey Beryozkin wrote:
>>>> On 31/08/11 10:48, Marek Potociar wrote:
>>>>>
>>>>>
>>>>> On 08/31/2011 11:08 AM, Sergey Beryozkin wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On 30/08/11 17:04, Marek Potociar wrote:
>>>>>>> Hi Sergey
>>>>>>>
>>>>>>> On 08/30/2011 12:53 PM, Sergey Beryozkin wrote:
>>>>>>>> On 29/08/11 17:04, Marek Potociar wrote:
>>>>>>>>> to do a typical GET request, which most likely will be the most
>>>>>>>>> prevailing use case, you SHOULD:
>>>>>>>>>
>>>>>>>>> - specify URI,
>>>>>>>>> - specify acceptable response media types
>>>>>>>>> - specify method (GET)
>>>>>>>>>
>>>>>>>>> With the current API proposal you can do:
>>>>>>>>>
>>>>>>>>> client.target(uri).request(accepted/type1, accepted/type2,
>>>>>>>>> ...).get();
>>>>>>>>>
>>>>>>>>> to me, it's as simple as it gets.
>>>>>>>>
>>>>>>>> Would you consider allowing for
>>>>>>>>
>>>>>>>>> client.target(uri).request(contentType, accepted/type1,
>>>>>>>>> accepted/type2, ...)
>>>>>>>> ?
>>>>>>>
>>>>>>> I did consider it in fact, but after playing with it for a while I
>>>>>>> concluded that multiple input arguments of the same
>>>>>>> type with different meaning based entirely on the order of strings
>>>>>>> (and in a vararg method) do not seem like a good
>>>>>>> idea. The above example looks quite ok, but cosider a real-life usage:
>>>>>>>
>>>>>>> client.target(uri).request("text/plain", "application/xml,
>>>>>>> "application/json").post(item); // which is which?
>>>>>>>
>>>>>>> It's not very readable IMO.
>>>>>>>
>>>>>>
>>>>>> You clipped there my comment about dropping a var support for
>>>>>> multiple accept headers in a transitional request() :-).
>>>>>> Is it really close to a common use case, having a programmatic client
>>>>>> setting multiple accepts ?
>>>>>> So what about
>>>>>> request(String ct);
>>>>>> request(String ct, String at);
>>>>>>
>>>>>> as I said your example above can be handle by using request() and
>>>>>> then setting multiple accept headers
>>>>>
>>>>> Varargs just add extra confusion but the problem "which is which" is
>>>>> there even for a method(String, String).
>>>>
>>>> what do you "which is which" ? I'm proposing to bin the option to
>>>> specify multiple accepts in a request(...) and have two well-document
>>>> option, one which tales a single arg - that is accept, the one which
>>>> takes 2 options takes Content-Type as the 1st param, Accept - as a 2nd one
>>>>
>>>>> Additionally, as I said, content type really belongs to the part where
>>>>> entity is provided).
>>>>>
>>>>
>>>> This is just too rigid - request is a transitional method and it does
>>>> make an exception for Accept, presumably to let people avoid typing
>>>> request(). I'm proposing to do another shortcut
>>>>
>>>>>>
>>>>>>> Also, I prefer keeping content type close to the entity:
>>>>>>
>>>>>>> client.target(uri).request("application/xml,
>>>>>>> "application/json").post(text(item));
>>>>>>>
>>>>>>> or generically:
>>>>>>>
>>>>>>> client.target(uri).request("application/xml,
>>>>>>> "application/json").post(entity(item, "text/plain"));
>>>>>>>
>>>>>>
>>>>>> Do you really like the above ?
>>>>>
>>>>> Yes I do :)
>>>>>
>>>>>> client.target(uri).request("text/plain", "application/json").post(item);
>>>>>>
>>>>>> Seems more readable to me.
>>>>>
>>>>> Not to me. It's perhaps a matter of taste, but I interpret the above
>>>>> as "Give me text or json in return for the posted
>>>>> item (represented as unknown media type)".
>>>>>
>>>>
>>>> Why you keep saying that :-) ? I've said twice that I proposed to drop a
>>>> request(String... accept) because IMHO it's not the most common case.
>>>> And have 2 methods one taking Accept only and one - Ct and Accept only
>>>> and thus in the latter case CT would still be close enough to post...
>>>>
>>>>>> By the way, does one really has to use entity wrapper all the time or
>>>>>> one of its static
>>>>>> helpers, no way to set content-type freely ?
>>>>>> I'm presuming the following is allowed
>>>>>> inv.header("Content-Type", "text/xml").accept("text/xml").post(new
>>>>>> Book()) ?
>>>>>
>>>>> Yes, if you want the extra freedom, there's the Invocation you can
>>>>> use. The difference is that invocation does not have
>>>>> named HTTP methods. It only has generic invoke/submit. Also, it does
>>>>> not have any header/entity mutators, but it
>>>>> provides access to HttpRequest. So the above code would need to be
>>>>> written as:
>>>>>
>>>>> invocation.asRequest().type("text/xml").accept("text/xml").entity(new
>>>>> Book()).method("POST"); // modify request freely
>>>>> invocation.invoke(); // invoke the modified request
>>>>>
>>>>> Yes, it's more verbose. But this is not the target use case of th API,
>>>>> although it's certainly good we provide the
>>>>> flexibility for users that truly need it.
>>>>>
>>>> Well, well...As said I was warming up but seeing these example makes me
>>>> dizzy...Having no explicit setter for CT without having to resort to the
>>>> above unreadable sequence ? I'm sorry - I do appreciate you are working
>>>> very hard - I honestly do.
>>>>
>>>>> Please, kindly look at the latest version of the API and the samples.
>>>>> I know there have been several changes in the API
>>>>> lately, but what I describe above is almost a week old stuff. To make
>>>>> it simpler, I just added a special example
>>>>> covering the Invocation API in larger detail.
>>>>>
>>>> Thanks for that
>>>> Sergey
>>>>
>>>>> Marek
>>>>
>>>>
>>>
>>>
>
>