There's no reason that you can't do either; or both.
In a point of sale context, tracking individual transactions makes a lot of sense. There, Robert's solution makes a lot of sense.
In a stock/warehouse context, you don't necessarily track transactions so much as "take inventory"; having an endpoint that allows the client to report their stock levels
I have 10 units
I have 7 units
I have 3 units
I have 20 units
makes a lot of sense.
Stock levels change for reasons other than "sales"; just something to keep in mind.
In theory, the stock level should be computable from the changes; but in some domains that is precisely the assumption that you want to verify. You would want to be able to compute the stock level two different ways and check for discrepancies (aka "shrinkage").
So I don't think the semantics are clear cut, based on the context you have provided.
As for the HTTP part; PUT [target-uri]
makes sense semantically when you are replacing one representation of a document with another. It's an UPSERT
- the second PUT to a resource is asking to overwrite the existing representation.
PUT /sales { Quantity = 5 }
PUT /sales { Quantity = 2 }
PUT /sales { Quantity = 3 }
says that the quantity of units sold is 3
, not 10
.
PUT /sales/1 { Quantity = 5 }
PUT /sales/2 { Quantity = 2 }
PUT /sales/3 { Quantity = 3 }
That's what 10
looks like
PUT /sales { Quantity : [5] }
PUT /sales { Quantity : [5,2] }
PUT /sales { Quantity : [5,2,3] }
That's another way of spelling 10
.
POST /sales { Quantity = 5 }
POST /sales { Quantity = 2 }
POST /sales { Quantity = 3 }
As far as HTTP is concerned, this is also acceptable. However, it's not a great choice on an unreliable network because messages are sometimes duplicated.
POST /sales { Quantity = 5 }
POST /sales { Quantity = 2 }
POST /sales { Quantity = 3 }
POST /sales { Quantity = 3 }
Is that 13
? or 10
?
PUT /sales/1 { Quantity = 5 }
PUT /sales/2 { Quantity = 2 }
PUT /sales/3 { Quantity = 3 }
PUT /sales/3 { Quantity = 3 }
That's unambiguously 10
PUT /sales { Quantity : [5,2,3] }
PUT /sales { Quantity : [5,2,3] }
That's unambiguously 10
PUT /sales/1 { Quantity = 5 }
PUT /sales/2 { Quantity = 2 }
PUT /sales/3 { Quantity = 3 }
PUT /sales/4 { Quantity = 3 }
That's unambigously 13
PUT /sales { Quantity : [5,2,3] }
PUT /sales { Quantity : [5,2,3,3] }
That's unambigously 13
POST /sales { TransactionId = 1 , Quantity = 5 }
POST /sales { TransactionId = 2 , Quantity = 2 }
POST /sales { TransactionId = 3 , Quantity = 3 }
POST /sales { TransactionId = 3 , Quantity = 3 }
10
POST /sales { TransactionId = 1 , Quantity = 5 }
POST /sales { TransactionId = 2 , Quantity = 2 }
POST /sales { TransactionId = 3 , Quantity = 3 }
POST /sales { TransactionId = 4 , Quantity = 3 }
13
(To be fair, HTTP does have support for conditional requests; you can lift some of the metadata from your domain specific protocol into the domain agnostic headers to eliminate some of the ambiguity -- if you can persuade the client to play along).
Of course, there are trade offs - HTML doesn't have native PUT support; if you are intending the clients of your API to be browsers, then you either need a protocol based on POST or you need code-on-demand extensions to convert the form submission from a POST to a PUT.