utilise un PUT avec des effets secondaires acceptables (REST)

9

Je veux créer un historique d'annulation chaque fois que l'utilisateur met à jour un formulaire. Parce que c'est une mise à jour, je veux utiliser une demande PUT. Cependant, j'ai lu que PUT ne devait avoir aucun effet secondaire .

Est-il acceptable d'utiliser PUT ici? Existe-t-il de meilleures alternatives?

PUT /person/F02E395A235

{
   time: 1234567,
   fields: {
      name: 'John',
      age: '41'
   }
}

Sur le serveur

doPut('person/:personId',
   // create a new person snapshot
)

Éditer:

L'historique sera visible pour l'utilisateur, appeler plusieurs fois entraînerait plusieurs versions.

La solution était de vérifier si la version était unique avant de la créer.

roo2
la source

Réponses:

11

Les rédacteurs de HTTP / 2 étaient beaucoup plus bavards sur leurs idées de ce que HTTP devrait faire, tout en conservant l'ancien sens. Voyons ce que le projet de spécification HTTP / 2 a à dire sur l'idempotence:

4.2.2. Méthodes idempotentes

Une méthode de demande est considérée comme "idempotente" si l'effet prévu sur le serveur de plusieurs demandes identiques avec cette méthode est le même que l'effet pour une seule demande de ce type. Parmi les méthodes de demande définies par cette spécification, PUT, DELETE et demande sécurisée les méthodes sont idempotentes.

Comme la définition de coffre-fort, la propriété idempotent ne s'applique qu'à ce qui a été demandé par l'utilisateur; un serveur est libre de consigner chaque demande séparément, de conserver un historique de contrôle des révisions ou d'implémenter d'autres effets secondaires non idempotents pour chaque demande idempotente .

L' effet prévu sur le serveur pour chacune de ces demandes PUT est de mettre à jour la ressource identifiée par cet URI . C'est exactement ce qui se passe dans votre cas.

Que vous décidiez de mettre à jour les ressources n'a pas vraiment d'importance ici. Si vous ne souhaitez pas créer une nouvelle version lorsque rien n'a changé, vous devrez comparer la charge utile de la demande PUT avec la version la plus récente (ou autrement identifiée) de la ressource, et lorsqu'aucune des propriétés n'a changé. vous pouvez choisir de ne pas créer de nouvelle version .


Votre modification:

L'historique sera visible pour l'utilisateur, appeler plusieurs fois entraînerait des multipleversions

En ce qui concerne la ressource, ce n'est pas un effet secondaire . La ressource à cet URI ne change pas (les mêmes propriétés obtiennent PUT). L'historique n'est que des métadonnées, car il est très probablement demandé par un URI différent ou avec des en-têtes de demande différents.

CodeCaster
la source
Sauf parce que vous répondez à mon problème spécifique: "est-il acceptable que PUT crée un historique visible par l'utilisateur", et donnez-moi une solution, merci
roo2
À quel problème est-ce une solution? Que la timepropriété soit mise à jour? Je pense que ce sont aussi des métadonnées, même si c'est dans la ressource.
CodeCaster
1
Le problème était que si plusieurs PUT étaient envoyés, l'utilisateur obtiendrait un long historique d'annulation avec des informations redondantes. vérifier l'unicité résout cela
roo2
12

HTTP distingue deux propriétés:

  • Idempotence
  • sécurité

L'idempotence est définie par la spécification comme suit:

Les méthodes peuvent également avoir la propriété " idempotence " en ce que (à part les problèmes d'erreur ou d'expiration) les effets secondaires de N> 0 requêtes identiques sont les mêmes que pour une seule requête. Les méthodes GET, HEAD, PUTet DELETEpartagent cette propriété. De plus, les méthodes OPTIONSet TRACE NE DEVRAIENT PAS avoir d'effets secondaires et sont donc intrinsèquement idempotentes.

Et la sécurité:

En particulier, la convention a été établie que les méthodes GETet NE DEVRAIENT PAS avoir la signification de prendre une action autre que la récupération. Ces méthodes doivent être considérées comme « sûres ». Cela permet aux agents utilisateurs de représenter d'autres méthodes, telles que , et , de manière spéciale, afin que l'utilisateur soit informé du fait qu'une action potentiellement dangereuse est demandée.HEADPOSTPUTDELETE

Naturellement, il n'est pas possible de garantir que le serveur ne génère pas d'effets secondaires suite à l'exécution d'une GETrequête; en fait, certaines ressources dynamiques considèrent cette fonctionnalité. La distinction importante ici est que l'utilisateur n'a pas demandé les effets secondaires et ne peut donc pas en être tenu responsable.

Notez que la sécurité implique l'idempotence: si une méthode n'a pas d'effets secondaires, la répéter plusieurs fois produira le même effet secondaire qu'une seule fois, à savoir aucune.

Cela met les méthodes en trois catégories:

  • coffre - fort (et donc aussi idempotent): GET, HEAD, OPTION,TRACE
  • idempotent mais pas nécessairement sans danger: PUT,DELETE
  • ni idempotent ni sûr: POST

PUT ne doit avoir aucun effet secondaire.

C'est faux. PUTest idempotent mais pas sûr. Le point entier de PUTest d'avoir un effet secondaire, la mise à jour à savoir une ressource. L'idempotence signifie que la mise à jour de la même ressource avec le même contenu plusieurs fois devrait avoir le même effet qu'une seule mise à jour.

Notez le dernier paragraphe de la section sur la sécurité [c'est moi qui souligne]:

Naturellement, il n'est pas possible de garantir que le serveur ne génère pas d'effets secondaires suite à l'exécution d'une GETrequête; en fait, certaines ressources dynamiques considèrent cette fonctionnalité. La distinction importante ici est que l'utilisateur n'a pas demandé les effets secondaires et ne peut donc pas en être tenu responsable .

Bien que cette phrase parle de GETsécurité, nous pouvons supposer que les auteurs ont également voulu appliquer le même raisonnement PUTet la même idempotence. IOW: PUTne devrait avoir qu'un seul effet secondaire visible par l' utilisateur , à savoir la mise à jour de la ressource nommée. Cela peut avoir d'autres effets secondaires, mais l'utilisateur ne peut en être tenu responsable.

Par exemple, le fait qu'il PUTsoit idempotent signifie que je peux le réessayer aussi souvent que je le souhaite: la spécification garantit que l'exécuter plusieurs fois sera exactement la même chose que l'exécuter une fois. Il est parfaitement valable de créer un arriéré d'anciennes révisions comme effet secondaire de ces multiples PUTdemandes. Cependant, si, à la suite de plusieurs tentatives, votre base de données se remplit d'un arriéré d'anciennes révisions, ce n'est pas mon problème, c'est le vôtre.

IOW: vous êtes autorisé à avoir autant d'effets secondaires que vous le souhaitez, mais

  1. il doit regarder l'utilisateur comme si ses demandes étaient idempotentes
  2. vous êtes responsable de ces effets secondaires, pas l'utilisateur
Jörg W Mittag
la source
Oui, l'idempotence concerne l'état de la ressource mise, pas tout autre état de serveur / service affecté par l'acte du PUT.
Marjan Venema
Upvote pour une grande explication, de la sécurité et de l'idempotence dans Rest
roo2
Grande explication. Cependant, vous faites plusieurs déclarations comme celle-ci: "L'intérêt de PUT est d'avoir un effet secondaire, à savoir la mise à jour d'une ressource." Cela semble être une contradiction à moins que vous ne vouliez dire quelque chose de différent par le terme «effet secondaire» de «quelque chose de secondaire ou non intentionnel qui se produit en plus de l'effet principal prévu».
MarredCheese
@MarredCheese: J'utilise le terme dans sa signification de programmation standard, ce qui signifie essentiellement "tout" résultat "qui n'est pas la valeur de retour".
Jörg W Mittag
Ah, bien sûr. Merci pour la clarification.
MarredCheese
1

Vous avez raison de dire que PUT ne doit avoir aucun effet secondaire , mais j'ajouterais quelque chose à cela.

PUT ne doit avoir aucun effet secondaire sur la ressource pour laquelle cette opération PUT est effectuée

Vous mettez à jour une personressource qui est identifiée comme F02E395A235, donc l'utilisation de PUT est correcte. Désormais, en règle générale, vous gardez également une trace des modifications qui ne sont pas visibles par l'entité appelante (consommateur du service REST). Cela n'ajoutera pas un nouvel élément dans la personressource. L'instantané historique ne sera pas accessible à l'aide du /person/point de terminaison. Je pense donc que le PUT devrait être parfaitement acceptable dans ce cas.

Aziz Shaikh
la source
1
Aucun effet secondaire sur la ressource mise, mais un certain nombre d'effets secondaires sur d'autres choses (compteurs, journalisation, traces d'audit, ...) sont parfaitement acceptables.
Marjan Venema