POST-ing lists of new resources to add/merge/remove
https://softwareengineering.stackexchange.com/questions/422341
-
22-03-2021 - |
Vra
I am working on the backend of a web application that exposes a REST-like API to the frontend of the application.
Currently, I am exposing a "Users" resource, where each user can be represented in JSON notation as:
{
"id": "asdfzxcv",
"name": "Morris",
"preferences": {
"dark_mode": true,
"tags": [ "tagA", "tagB" ]
}
}
I currently expose this user at the endpoint GET /api/v1/users/<user-id>
.
Now, I have been given the requirement that the frontend should be able to:
- Submit a list of tags to be added to the user's preferences
- Submit a list of tags to be removed from the user's preferences
- Submit a list of tags to replace the user's preferred tags
Originally, I was thinking the client could do PUT (or DELETE) /api/v1/users/<user-id>/preferences/tags/tagA
, but this would entail making multiple requests to add/remove multiple new preferences, which would be very wasteful.
How should I design the URL paths to handle this case?
One possible solution is to use query parameters to change the behavior:
POST /api/v1/users/<user-id>/preferences/tags
(default action: update/merge)POST /api/v1/users/<user-id>/preferences/tags?action=replace
POST /api/v1/users/<user-id>/preferences/tags?action=delete
Or I could have 3 separate URLs:
POST /api/v1/users/<user-id>/preferences/tags
(default action: update/merge)POST /api/v1/users/<user-id>/preferences/tags/replace
POST /api/v1/users/<user-id>/preferences/tags/delete
Oplossing
If you want to be "more REST-ish", you can model tags
as a single "collection" resource, and support multiple HTTP methods on it:
- The resource at
/api/v1/users/XXX/preferences/tags
represents the list of tags for userXXX
GET /api/v1/users/XXX/preferences/tags
returns a representation of all the current tags for that userPUT /api/v1/users/XXX/preferences/tags
replaces the list with a completely new listPOST /api/v1/users/XXX/preferences/tags
adds a tag to the listDELETE /api/v1/users/XXX/preferences/tags
removes all tags from the listPATCH /api/v1/users/XXX/preferences/tags
allows changes to the collection
It's that last one which gives you the power to do multiple adds or deletes in one request, even in the same request. All you need is to pick a representation for the changes, which could be something like this:
{
"add": ["foo", "bar"],
"remove": ["tagA"]
}
(You could also use a standard format, like JSON Patch but it seems less suitable for managing lists.)