Pregunta

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
¿Fue útil?

Solución

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 user XXX
  • GET /api/v1/users/XXX/preferences/tags returns a representation of all the current tags for that user
  • PUT /api/v1/users/XXX/preferences/tags replaces the list with a completely new list
  • POST /api/v1/users/XXX/preferences/tags adds a tag to the list
  • DELETE /api/v1/users/XXX/preferences/tags removes all tags from the list
  • PATCH /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.)

Licenciado bajo: CC-BY-SA con atribución
scroll top