- From: Markus Lanthaler <markus.lanthaler@gmx.net>
- Date: Fri, 28 Feb 2014 17:11:22 +0100
- To: "'Ryan J. McDonough'" <ryan@damnhandy.com>
- Cc: <public-hydra@w3.org>
On Tuesday, February 18, 2014 10:08 PM, Ryan J. McDonough wrote:
> On Feb 18, 2014, at 10:55 AM, Markus Lanthaler wrote:
> > On Tuesday, February 18, 2014 12:22 AM, Ryan J. McDonough wrote:
> >> In my mind, the equivalent in Hydra would be something like so:
> >>
> >> {
> >> "@context": "http://www.w3.org/ns/hydra/context.jsonld",
> >> "@id": "http://example.com/me/cart",
> >> "operation": {
> >> "method": "POST",
> >> "expects": {
> >> "@type": "AddItemToCartRequest",
> >
> > Yeah, but without that type information.
>
>
> Yes.
>
> >
> >
> >> "supportedProperty": [
> >> {
> >> "property": {
> >> "@id": "productId",
> >> "@type": "rdf:Property",
> >> "range":
> >> "http://www.w3.org/2001/XMLSchema#integer"
> >> },
> >> "required": true
> >> },
> >> {
> >> "property": {
> >> "@id": "productVarientId",
> >> "@type": "rdf:Property",
> >> "range":
> >> "http://www.w3.org/2001/XMLSchema#integer"
> >> },
> >> "required": true
> >> },
> >> {
> >> "property": {
> >> "@id": "quantity",
> >> "@type": "rdf:Property",
> >> "range":
> >> "http://www.w3.org/2001/XMLSchema#integer"
> >> },
> >> "required": true
> >> }
> >> ]
> >> }
> >> }
> >> }
> >>
> >> I can use @type to be more specific about the intent of this
> >> message. The server would see this message come as a call to
> >> action and there's likely a handler on the server side to
> >> process an "AddItemToCartRequest."
> >
> > I can't help, but to me this looks like a perfect example of RPC:
> >
> > addItemToCart(productId, productVarientId, quantity)
>
> How did you arrive at that?
> If you want to look at it that way, the
> sure. However, I see it more like this:
>
> curl -X POST -H "Content-Type: application/ld+json" -d '{"@context":
> "http://example.com/cart", "@type": "AddItemToCartRequest",
> "productId": "1789", "productVarientId": "1641", "quantity": 2}'
> http://example.com/my/cart
Because the first analogy that came to my mind was
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
</soap:Header>
<soap:Body>
<e:AddItemToCartRequest xmlns:e="http://example.org/shopping">
<e:productId>1789</e:productId>
<e:productVarientId>1641</e:productVarientId>
<e:quantity>2</e:quantity>
</e:AddItemToCartRequest>
</soap:Body>
</soap:Envelope>
> Sure, there's nothing stopping you from sending wrapping either of the
> above in a function like you've described, but that function would
> still have to format the message and send it over HTTP POST. I'm still
> working with the uniform interface of HTTP. The only difference is that
> the message being sent indicates intent. What I want to do is expressed
> in the message rather than around it.
>
> > In REST, you would much rather want to modify its state by PUTing a
> > new representation.
>
> Why must this always the case? As I've illustrated with the HTML forms
> example already, this is not the model that HTML forms work with today.
> Unless of course you disagree with the statement that HTML exhibits a
> number of RESTful qualities.
It must not but if you want to benefit from the uniform interface you should
use a method with some semantics. POST is a catch-all with no semantics. Of
course you can tunnel everything over a POST (as SOAP/WSDL did in its early
days) but you lose a number of, sometimes important, aspects. If you PUT,
and your request fails. You simply repeat it. If your POST fails, it's not
obvious how to react. I don't know how many HTML forms I've seen that had
some JavaScript code to prevent multiple POSTs.
[...]
> >> More importantly,
> >> I know what the intent of the user is because they sent me a message
> >> requesting to add the product to the cart as opposed to POSTing a
> >> http://schema.org/Product instance to a URL.
> >
> > POST is always tricky as it has so little semantics. If we would
> > replace that example with PUTing a new shopping cart representation
> > to the URL of my shopping cart, the situation would be quite different.
> > The intent would be quite clear without requiring a special
> > AddItemToCartRequest message.
>
> I assuming that the interaction you're talking about is that the client
> dereferences a representation of the current state of the cart. When
> they want to add something to that, the modify the cart locally and
> issue a PUT to replace the current state of the cart, correct?
Correct
> Assuming that's true, the server has some work to do to determine what
> happened to the cart. Did I add an item? Did I change the quantity? Did
> I change the color of the thing I ordered? Did I remove the item? And
> "UpdateCartOperation" is just too vague and the expectations that a
> client may have on this operation could yield unexpected results.
Does it have to know? It can simply discard the existing cart and replace it
with a new one. You get the additional advantage that the complete cart is
in the request which might be helpful if you need to scale your system.
[...]
> > So you say sending an AddItemToCartRequest is preferable than PUTing
> > a new ShoppingCart representation?
>
> If I had my druthers, yes this is exactly what I'd do. And I'd send it
> over POST and not PUT. You can imagine that by adding n items to my
> cart, this may or may not have an affect on available inventory to
> there potential shoppers. Perhaps my store will reserve the quantity in
> your cart for some period of time until you check out? Since this
> operation will now have side effects on other resources, say the
> catalog and available inventory, PUT is not appropriate.
Why is PUT not appropriate in that case (if you send the complete shopping
cart)?
> This is pretty
> much the same way HTML forms work today, but you're only dealing with
> key/value pairs. But because I'm affecting other resources, I want to
> use POST.
>
> From a performance perspective, smaller messages tend be faster over
> the wire.
Right, but HTTP/REST wasn't optimized for that at all. It is a
coarse-grained hypermedia system. If you are concerned about performance,
you should go a level deeper and operate on a TCP or UDP socket and send
optimized (probably binary) messages.
> Using a PUT to update the entire cart would get slower
> because now my cart grows with every addition and will continually get
> bigger. Furthermore, I don't know why someone sent back their cart
> using a PUT.
Because they want to replace their current cart with the new one!?
> All I know is that they issued a PUT. I you haven't
> guessed yet, I'm a bit more of fan of Domain Driven Design and CQRS. In
> short, I don't like making my write model the same as my read model. I
> also can optimize writes differently than I do for my write model.
What exactly do you mean by "write model" and "read model"? The data model?
The way it is serialized? The way you implement it?
> But we're going off the rails a bit here, and I want to go back to
> Mark's original point. This debate we are having go back to Mark's
> DELETE/Clear example. What your solution seems to be advocating is
> collecting the items selected by the client and adding them to a data
> structure that models a ShoppingCart. In your solution, your client
> would be be issuing a PUT to the cart URI. You might call this
> "UpdateCartOperation" but all you've really done is replace the state
You could also just re-use Hydra's (still existing)
ReplaceResourceOperation.
> of cart with no content of what the update entailed. This operation
> lacks visibility in that one cannot determine if I added a new item to
> the cart, removed an item from the cart, or simply updated a quantity.
Right, and exactly that's the point of the uniform interface constraint. You
don't want three interfaces but just a single one. You want to hide those
details behind a uniform interface. HTTP isn't concerned about these things.
Neither are intermediaries. The only ones who are, are the client and the
server.
> These are 3 distinct activities that affect the same concept. If we
> called your operation " UpdateCartOperation", developers will have
> different expectations around the kind of response that gets returned.
And how is that a problem? They would get the new resource back... or even
just a 204 No Content.
Cheers,
Markus
--
Markus Lanthaler
@markuslanthaler
Received on Friday, 28 February 2014 16:12:01 UTC