Reputation: 3782
So let's say you have two entities Product
and Category
. One product can have multiple categories and one category can have multiple products.
When it comes to the API design you want to create endpoints to add / remove categories from a product. The first approach would be this
which is fine but I normally use POST to create a new resource and send back a 201. Another approach would be
and send a bool if you want to add / remove it. The second approach seems to fit better (just return a 200) but the body payload looks a bit ugly.
{
"add": true
}
Or call the patch route without a body payload and just toggle it? If that product is linked to the category remove it, otherwise add it.
What is the best practise for adding / removing a resource from another one?
Upvotes: 0
Views: 326
Reputation: 57257
I suggest that you review Jim Webber's 2011 talk.
If we are doing REST, then we are achieving our goals using general purpose message semantics. When HTTP is our application of choice, then our general purpose message semantics are those associated with transferring documents over a network.
You deliver information to a system by proposing changes to a resource.
One common form of change is a modification of a representation of the resource. In your case, that would suggest a resource that is a list of all categories associated with the product. So you would GET
the current representation of that resource, make local changes to your copy, then PUT
your updated representation back to the same resource.
GET /products/1/categories
200 OK
Content-Type: text/plain
A
B
C
D
PUT /products/1/categories
Content-Type: text/plain
A
B
E
F
G
200 OK
When the representation of the resource is very large (relative to the size of the HTTP headers), and the edits you want to support are often going to be small, then it can make sense to support PATCH, accepting one of the standardized patch document formats.
The other approach is to POST to the resource a document that describes some change to be made. See It is okay to use POST, by Roy Fielding:
POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.”
This is how most of the pre-javascript HTML web worked; HTML forms would tell clients how to create an application/x-www-form-urlencoded
document that the target resource would know how to interpret.
POST /products/1/categories
Content-Type: application/x-www-form-urlencoded
remove=C,D&add=E,F,G
and that worked great; the web was catastrophically successful.
Forms work because the text/html media type has a standardized definition of forms, and how to process them. You can do something similar with your own media types; defining within the representations how to find interesting links that advertise the capabilities of some resource.
Another approach is to use [web links]; you define the semantics of a link relation
the relation
http://example.org/abc
indicates that the target resource is capable of understanding and handling POST requests containingapplication/prs.xyz+json
documents)
And then you embed those link relations either into your representations, into the HTTP headers, or both. Then any client that understands the semantics of the link relation and the associated media types will be able to take advantage of the advertised capability.
See RFC 5023 to see how this approach was applied in Atom.
Upvotes: 1