¿Está bien cambiar parcialmente una colección con PUT o DELETE?

21

Tengo una colección de productos en un grupo de productos, por ejemplo:

product-groups/123/products
  1. Si necesito agregar a la colección, ¿está bien que solo pase algunos productos con PUT?

  2. Si necesito eliminar algunos productos de la colección, ¿está bien que pase los datos del filtro (una matriz de ID) con DELETE?

¿Cuál es la mejor manera de implementar la funcionalidad en el espíritu de ReST?

Editar: los artículos son enlaces a entidades separadas, básicamente identificaciones de productos.

usuario151851
fuente
¿Los artículos en el grupo de productos separan los recursos administrados en otro lugar? ¿O son solo parte de la colección del grupo de productos? Si están separados, ¿pueden los productos pertenecer a múltiples grupos de productos?
Martijn Pieters
2
quizás PATCH Esta especificación define el nuevo método HTTP / 1.1 [RFC2616], PATCH, que se utiliza para aplicar modificaciones parciales a un recurso.
Esailija
Un producto (ID) puede pertenecer a varios grupos de productos.
user151851
¿Existe una forma conocida (mejor práctica) de decir cómo PARCHE, es decir, agregar o eliminar productos en la colección?
user151851
Pregunta similar en SO stackoverflow.com/questions/411462/…
Luke Puplett

Respuestas:

10

En general, tiene un punto final que representa la colección completa de x :

/products

Por ejemplo, quieres actualizar un solo producto, se hace un PUT a /products/{id}. Si desea actualizar parcialmente un solo producto (sin actualizar todos los campos), también puede usar un PATCH para /products/{id}. Lo mismo ocurre con la eliminación de una sola entidad ( DELETE to /products/{id}).

Si desea apuntar a un único recurso, califique a través de la ruta, qué recurso único desea modificar.

La única acción que rompe el esquema es la creación de un recurso. Cuando cree un recurso, apunte a la colección como un todo, diga POST a /products.

Dicho esto, debe quedar claro, que el objetivo para las operaciones que afectan a la colección en su conjunto, debe ir al punto final de recolección apropiado.

Por ejemplo, si desea recuperar un subconjunto de productos que son rojos, lo solicita

GET a /products?colour=red.

Entonces, si desea eliminar todo esto, BORRAR /products?colour=red . O si desea eliminar algunos de los productos mediante id, puede ELIMINAR /products?id=1&id=2&id=3 .

¿Qué pasa con la creación masiva de recursos? PUBLICA tu colección [{...},{...},{...}]simplemente en /products. Lo mismo aplica para PUT y PATCH .

Eso es realmente sencillo.

Para responder tu pregunta:

Si necesito agregar a la colección, ¿está bien que solo pase algunos productos con PUT?

No solo está bien, le recomendamos que lo haga así.

Si necesito eliminar algunos productos de la colección, ¿está bien que pase los datos del filtro (una matriz de ID) con DELETE?

Eso está bien. Como escribió Eneko Alonso, a veces hay operaciones masivas encapsuladas a través de puntos finales "controladores", es decir, se utiliza una POST para desencadenar operaciones (complejas).

Thomas Junk
fuente
2
PUT es una operación de reemplazo. Llamar a PUT en un punto final de colección con "algunos productos" debería eliminar (en el caso del OP, eliminar la relación con) cualquier producto que no esté incluido en la lista de "algunos productos". Si bien podría usarse para agregar elementos, también debería eliminar elementos que no son (en mi opinión) lo que espera el OP. Debe revisar su respuesta a su primera pregunta en consecuencia.
claytond
@claytond: supongo que la respuesta está bien, siempre y cuando se realice una actualización parcial PATCHy un reemplazo completo a través de PUT.
9000
44
@ 9000. Por supuesto, pero la respuesta actualmente dice "se le anima a ... agregar a la colección ... [al] pasar [ing] solo algunos productos con PUT". Eso es ciertamente incorrecto. Animado a publicar. Capaz de PONER ... pero solo pasando todos (no algunos) elementos.
claytond
5

Por lo general, los métodos REST están destinados a operar en una sola entidad / objeto (CRUD).

Hay varias opciones:

  • Trate sus colecciones como entidades y actualícelas a través de POST
  • Crear operaciones alternativas que no sean REST

El primero sigue los estándares REST, pero puede ser costoso, ya que los objetos / entidades de su colección pueden ser muy grandes (actualizar un grupo que tiene miles de productos solo para agregar / eliminar un producto sería una gran solicitud).

La segunda opción es preferida por muchas API, como una forma de extender REST más allá de las operaciones CRUD.

Por ejemplo:

GET product-groups/123/products (list all the products in the group)
POST product-groups/123/products/append (POST a list of new product ids to append to the group)
POST product-groups/123/products/remove (POST a list of product ids to remove from the group)

Muchas API usan siempre POST para estas operaciones extendidas, pero nada lo limita a usar otros métodos http (aparte de la limitación de GET y DELETE para tener un cuerpo vacío)

Eneko Alonso
fuente
Claro, hay algunos métodos para alcanzar la meta. ¿Cuál es la mejor práctica? ¿Cuál será más a prueba de futuro?
user151851
44
@ user151851: El cumplimiento total de REST (si existe) es un objetivo elevado. El esquema del enfoque aquí parece más realista, en la medida en que intenta emplear un enfoque que realmente se está utilizando en el "mundo real", convirtiéndolo, en esencia, en un estándar de facto. Eso es tan a prueba de futuro como lo que vas a obtener.
Robert Harvey
2
¿No presentamos verbos personalizados con "agregar" y "eliminar" en la URL? De esa manera tendremos que explicar cómo usar la API. ¿No deberíamos reutilizar lo que tenemos, es decir, los métodos HTTP? En cuyo caso las acciones son bien conocidas.
user151851
77
Para cualquiera que se encuentre con esta respuesta: está mal. Como se mencionó en @ user151851, esto introduce verbos en la URL que es tan poco RESTful como puedes obtener. Con respecto a la pregunta real, no tengo una gran respuesta, pero esta no es la respuesta.
umbrae
¿Podría la "extensión" estar más orientada a los recursos al hacer products/collectionque devuelva un 'sobre' de elementos y el contenido del sobre cambie a través de un PUT? Como "aquí es exactamente cómo quiero que sean los elementos de la colección".
Luke Puplett el
3

Solo para precisar respuestas / comentarios anteriores.

Según mi conocimiento, POST es el método para agregar elementos individuales a la colección.

DELETE a su vez, es el método para eliminar un solo elemento de la colección. Ambos escenarios son perfectamente RESTful.

Sin embargo, debe usar el URI apropiado para referir un solo elemento o la colección completa.

Por ejemplo, para agregar un elemento a la colección, debe PUBLICAR datos en el siguiente URI:

https://www.factory.net/products/

Para eliminar un solo producto de la colección, puede usar el método DELETE enviando solicitud a algo como:

https://www.factory.net/products/108/

El método PATCH puede usarse para actualizar algunos elementos dentro de la colección. Por ejemplo, cuando solo necesita actualizar un campo en un elemento. PONER una representación completa de recursos para una colección muy grande puede ser una operación muy costosa.

Lukasz
fuente
2

En principio, todas las operaciones RESTful son válidas en una colección, pero asegúrese de comprender cómo se aplica la semántica de los verbos a una colección:

  • PUT es un reemplazo completo .

    • Si pone un singleton (p /item/{id}. Ej. ) Y lo deja namefuera, debe borrarse o establecerse en nulo o algo similar.
    • Si PONE a una colección y no incluye un artículo, debe eliminarse de esa colección.

    Si bien se puede usar un PUT para agregar elementos, debe enviar "todos" los elementos. El envío de "algunos" elementos debería resultar en la eliminación (supongo que esto no es lo que desea el OP).

  • ELIMINAR es más intuitivo. Es válido eliminar la colección o cualquier subconjunto filtrado de la misma. Solo los elementos incluidos en el filtro deben verse afectados.

  • PARCHE también es válido. En teoría, se supone que debe proporcionar una lista de "operaciones". Por ejemplo, técnicamente debería enviar algo como:

    [{ 
        "action": "update",
        "id": <id>,
        "value": {...}
    },{
        "action": "add",
        "value": {...}
    }, ...]
    

    En la práctica, es más común ver una API que acepta una lista parcial de objetos donde cada elemento se procesa utilizando una lógica UPSERT (actualización o inserción).

  • Técnicamente, POST debe procesar la entrada "de acuerdo con la semántica específica del recurso".

    • En la práctica, POST se usa normalmente para operaciones de "creación".
    • Sin embargo, POST también es el verbo utilizado para llamadas no estándar. Si bien existe un debate vigoroso sobre si los puntos finales de acción son estrictamente RESTful (estoy del lado de los "no"), POST es el verbo apropiado si estaba enviando una solicitud a un punto final como {resource}/activate.

NOTA: Cuando utilice operaciones que no sean GET en colecciones, considere cuidadosamente la definición de éxito y fracaso. REST no le brinda una buena forma de comunicar el éxito parcial. Un buen valor predeterminado es asumir que ejecutará la operación en una transacción con un criterio de éxito de todo o nada. Si esto no es lo que desea, probablemente no debería estar interactuando directamente con la colección.

Claytond
fuente