I will try to be exhaustive about the possible solutions that you might use.
As you wrote, I consider that a product has the following attributes : id, name, availability
1. Designing a resource for each attributes
- /products/555/name:
GET
returns the current name of the product id 555. PUT newname
modify the current name of the product id 555 with newname
- /products/555/availability:
GET
returns the current availability. PUT 99
modify the current availability to99
.
... and so on ...
Notice that the resources are not "method oriented", they correspond to a concept (name, availability, etc. of a product) that could be updated, retrieved, deleted, etc. and not restrained to a particular function.
Notice also that i'm not describing what are the different internally method call when a resource receive a GET
or PUT
request. That's totally orthogonal. I will write a little note about it, at the end of the answer.
Major drawback of this approach: to update x attributes, a client needs to send x requests... You clearly see that it could be tedious for a client to do that and also bandwidth consuming. But if it's ok, then go ahead.
2. A resource with all of the attributes
- /products/555 : contains every attributes of a product (name, availability, etc.). A
GET
returns these attributes. For updating them, you have 2 possibilities:
2.1 updating with PUT
PUT method is intended to fully update the resource representation. It means that your client needs to sends every attributes of a product in the payload.
Imagine that the current representation of resource /products/555 is :
{ "name": "bread", "availability": 10 }
If you want to update just the availability to 99
, you need to send the full representation of the resource, like that:
PUT /products/555 { "name": "bread", "availability": 99 }
Major drawback of this approach: A client that want to update one field will need to send the whole representation of the resource.
2.2 updating with PATCH
PATCH verb aims to partially update a resource representation.
Considering the current representation of the product is { "name": "bread", "availability": 10 }
. If a client want to update only the availability
, it will send :
PATCH /products/555 { "availability": 42 }
Be careful, because PATCH is not idempotent. It means that this request:
PATCH /products/555 { "availability": 42 }
can leads to have the following resource representation :
{ "name": "bread", "availability": 42 }
or
{ "name": "sugar", "availability": 42 }
Thus, it breaks idempotency... that PUT
guarantee :) ! (since with PUT
you send the full representation in the request body)
You could also update several attributes, if your product resource have it. That's obviously less bandwitdh consuming that the solution described in 1.
Note: Underlying methods call
As said previously, methods call are orthogonal to the design of your resources.
In your case, you have some fine grained method to update just one attribute of the Product class... that's ok.
But you could encapsulate this one in a coarse-grained method, something like this:
Product updateProduct(Product p) {
p.updateName();
p.changeAvailability();
...
return p;
}
PATCH
verb ?