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

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

From: Sergey Beryozkin <sberyozkin_at_talend.com>
Date: Wed, 31 Aug 2011 12:19:28 +0100

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.

Are you concerned about POSTs containg no CT ?
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

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


-- 
Sergey Beryozkin
http://sberyozkin.blogspot.com
Talend - http://www.talend.com