- 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