Est-il OK de modifier partiellement une collection avec PUT ou DELETE?

21

J'ai une collection de produits dans un groupe de produits, par exemple:

product-groups/123/products
  1. Si je dois ajouter à la collection, est-ce OK que je ne passe que certains produits avec PUT?

  2. Si je dois supprimer certains produits de la collection, est-ce OK que je passe des données de filtre (un tableau d'ID) avec DELETE?

Quelle est la meilleure façon de mettre en œuvre la fonctionnalité dans l'esprit de ReST?

Modifier: les articles sont des liens vers des entités distinctes, essentiellement des ID de produits.

user151851
la source
Les articles du groupe de produits sont-ils gérés séparément? Ou sont - ils seulement une partie de la collection du groupe de produits? S'ils sont séparés, les produits peuvent-ils appartenir à plusieurs groupes de produits?
Martijn Pieters
2
peut-être PATCH Cette spécification définit la nouvelle méthode HTTP / 1.1 [RFC2616], PATCH, qui est utilisée pour appliquer des modifications partielles à une ressource.
Esailija
Un produit (ID) peut appartenir à plusieurs groupes de produits.
user151851
Existe-t-il un moyen bien connu (meilleure pratique) de dire comment PATCH, c'est-à-dire ajouter ou supprimer des produits dans la collection?
user151851
Question similaire sur SO stackoverflow.com/questions/411462/…
Luke Puplett

Réponses:

10

En général, vous avez un point de terminaison qui représente l'ensemble de la collection de x :

/products

Dites, vous souhaitez mettre à jour un seul produit, vous faites un PUT à /products/{id}. Si vous souhaitez mettre à jour partiellement un seul produit (pas mettre à jour tous les champs), vous pouvez également utiliser un PATCH pour /products/{id}. Il en va de même pour la suppression d'une seule entité ( DELETE to /products/{id}).

Si vous souhaitez cibler une seule ressource, vous qualifiez via path, quelle ressource unique , vous souhaitez modifier.

La seule action qui rompt le schéma est la création d'une ressource. Lorsque vous créez une ressource, vous ciblez la collection dans son ensemble, dites POST to /products.

Cela dit, il doit être clair que l'objectif des opérations affectant la collection dans son ensemble doit aller au point de terminaison de collecte approprié.

Par exemple, vous souhaitez récupérer un sous-ensemble de produits qui sont rouges, vous le demandez par

GET to /products?colour=red.

Donc, si vous souhaitez supprimer tout cela, vous SUPPRIMEZ /products?colour=red . Ou si vous souhaitez supprimer certains produits via id, vous pouvez SUPPRIMER /products?id=1&id=2&id=3 .

Qu'en est-il de la création en masse de ressources? POSTEZ votre collection [{...},{...},{...}]simplement /products. Il en va de même pour PUT et PATCH .

C'est vraiment simple.

Pour répondre à vos questions:

Si j'ai besoin d'ajouter à la collection, est-ce OK que je ne passe que certains produits avec PUT?

Ce n'est pas seulement OK, vous êtes encouragé à le faire comme ça.

Si je dois supprimer certains produits de la collection, est-ce OK que je passe des données de filtre (un tableau d'ID) avec DELETE?

C'est bon. Comme l'a écrit Eneko Alonso, il y a parfois des opérations en bloc encapsulées via des points de terminaison "contrôleur", c'est-à-dire qu'un POST est utilisé pour déclencher des opérations (complexes).

Thomas Junk
la source
2
PUT est une opération de remplacement. L'appel de PUT sur un point de terminaison de collecte avec "certains produits" devrait supprimer (dans le cas du PO, supprimer la relation avec) tout produit qui ne figure pas dans la liste de "certains produits". Bien qu'il puisse être utilisé pour ajouter des éléments, il devrait également supprimer des éléments qui ne sont pas (à mon avis) ce que le PO attend. Vous devez réviser votre réponse à leur première question en conséquence.
claytond
@claytond: Je suppose que la réponse est correcte, tant qu'une mise à jour partielle est effectuée avec PATCH, et un remplacement complet via PUT.
9000
4
@ 9000. Bien sûr, mais la réponse dit actuellement "vous êtes encouragés à ... ajouter à la collection ... [en] passant [seulement] seulement certains produits avec PUT". C'est certainement incorrect. Encouragé à POST. Capable de PUT ... mais seulement en passant tous (pas certains) éléments.
claytond
5

Habituellement, les méthodes REST sont destinées à fonctionner sur une seule entité / objet (CRUD).

Il existe plusieurs options:

  • Traitez vos collections comme des entités et mettez-les à jour via POST
  • Créer des opérations alternatives non REST

Le premier suit les normes REST, mais peut être coûteux, car vos objets / entités de collection peuvent être très volumineux (la mise à jour d'un groupe qui a des milliers de produits juste pour ajouter / supprimer un produit serait une lourde demande).

La deuxième option est préférée par de nombreuses API, comme un moyen d'étendre REST au-delà des opérations CRUD.

Par exemple:

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)

De nombreuses API utilisent toujours POST pour ces opérations étendues, mais rien ne vous limite à utiliser d'autres méthodes http (autres que la limitation de GET et DELETE pour avoir un corps vide)

Eneko Alonso
la source
Bien sûr, il existe quelques méthodes pour atteindre l'objectif. Laquelle est la meilleure pratique? Lequel sera plus pérenne?
user151851
4
@ user151851: La conformité REST totale (s'il y a une telle chose) est un objectif noble. Le schéma de l'approche ici semble plus réaliste, dans la mesure où il tente d'employer une approche qui est réellement utilisée dans le «monde réel», ce qui en fait, par essence, une norme de facto. C'est à peu près aussi évolutif que possible.
Robert Harvey
2
N'introduisons-nous pas des verbes personnalisés en utilisant "ajouter" et "supprimer" dans l'URL? De cette façon, nous devrons expliquer comment utiliser l'API. Ne devrions-nous pas réutiliser ce que nous avons, c'est-à-dire les méthodes HTTP? Dans ce cas, les actions sont bien connues.
user151851
7
Pour toute autre personne qui arrive dans cette réponse: c'est faux. Comme @ user151851 l'a mentionné, cela introduit des verbes dans l'URL qui est à peu près aussi non-RESTful que possible. En ce qui concerne la vraie question, je n'ai pas une bonne réponse, mais celle-ci n'est pas la.
umbrae
L'extension pourrait-elle être plus orientée vers les ressources en la faisant products/collectionrenvoyer une «enveloppe» d'articles et le contenu de l'enveloppe modifié via un PUT? Comme, "voici exactement comment je veux que les articles de la collection soient".
Luke Puplett
3

Juste pour préciser les réponses / commentaires précédents.

Selon mes connaissances, POST est la méthode pour ajouter des éléments uniques à la collection.

SUPPRIMER à son tour, est la méthode pour supprimer un seul élément de la collection. Les deux scénarios sont parfaitement RESTful.

Cependant, vous devez utiliser l'URI approprié pour référencer un seul élément ou la collection entière.

Par exemple, pour ajouter un élément à la collection, vous devez POSTER les données sur l'URI suivant:

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

Pour supprimer un seul produit de la collection, vous pouvez utiliser la méthode DELETE pour envoyer une demande à quelque chose comme:

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

La méthode PATCH peut être utilisée pour mettre à jour certains éléments de la collection. Par exemple, lorsque vous avez seulement besoin de mettre à jour un champ dans un élément. METTRE une représentation complète des ressources pour une très grande collection peut être une opération très coûteuse.

Lukasz
la source
2

En principe, toutes les opérations RESTful sont valides sur une collection, mais assurez-vous de comprendre comment la sémantique des verbes s'applique à une collection:

  • PUT est un remplacement complet .

    • Si vous mettez un singleton (par exemple /item/{id}) et omettez name, il doit être effacé ou défini sur null ou quelque chose de similaire.
    • Si vous placez une collection et n'incluez pas d'élément, il doit être supprimé de cette collection.

    Bien qu'un PUT puisse être utilisé pour ajouter des éléments, vous devez envoyer "tous" les éléments. L'envoi de "certains" articles devrait entraîner des suppressions (je suppose que ce n'est pas ce que désire le PO).

  • DELETE est plus intuitif. Il est valide de supprimer la collection ou tout sous-ensemble filtré de celle-ci. Seuls les éléments inclus dans le filtre doivent être affectés.

  • PATCH est également valide. En théorie, vous êtes censé fournir une liste "d'opérations". Par exemple, vous devez techniquement envoyer quelque chose comme:

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

    En pratique, il est plus courant de voir une API qui accepte une liste partielle d'objets où chaque élément est traité à l'aide d'une logique UPSERT (mise à jour ou insertion).

  • Techniquement, POST devrait traiter l'entrée "selon la sémantique spécifique de la ressource".

    • En pratique, POST est normalement utilisé pour les opérations de "création".
    • Cependant, POST est également le verbe utilisé pour les appels non standard. Bien qu'il y ait un débat vigoureux sur la question de savoir si les points de terminaison d'action sont strictement RESTful (je suis du côté des «non»), POST est le verbe approprié si vous soumettez une demande à un point de terminaison comme {resource}/activate.

REMARQUE: lorsque vous utilisez des opérations non GET sur des collections, examinez attentivement la définition du succès et de l'échec. REST ne vous donne pas un bon moyen de communiquer un succès partiel. Une bonne valeur par défaut consiste à supposer que vous exécuterez l'opération dans une transaction avec des critères de réussite tout ou rien. Si ce n'est pas ce que vous voulez, vous ne devriez probablement pas interagir directement avec la collection.

claytond
la source