web-dev-qa-db-fra.com

Pourquoi la méthode PATCH n'est pas idempotente?

Je me posais des questions à ce sujet.

Supposons que j'ai une ressource user avec les champs id et name. Si je veux mettre à jour un champ, je pourrais simplement faire une demande PATCH à la ressource comme celle-ci

PATCH /users/42
{"name": "john doe"} 

Et puis l'application mettra à jour le nom de l'utilisateur.

Mais pourquoi si je répète cette demande, le résultat serait différent?

Selon RFC 5789

PATCH n'est ni sûr ni idempotent

54
mattecapu

Une demande PATCH peut être idempotente, mais ce n'est pas obligatoire. C'est la raison pour laquelle il est caractérisé comme non-idempotent.

Que PATCH puisse être idempotent ou non dépend fortement de la façon dont les changements requis sont communiqués.
Par exemple, si le format du correctif est sous la forme de {change: 'Name' from: 'benjamin franklin' to: 'john doe'}, alors toute demande PATCH après la première aurait un effet différent (une réponse d'échec) que la première demande.
Une autre raison de non-idempotence peut être que l'application de la modification à autre chose que la ressource d'origine peut rendre la ressource invalide. Ce serait également le cas si vous appliquez la modification plusieurs fois.

41

Je pense que la réponse claire lorsque PATCH n'est pas idempotent est ce paragraphe de la RFC 5789:

Il existe également des cas où les formats de correctifs n'ont pas besoin de fonctionner à partir d'un point de base connu (par exemple, l'ajout de lignes de texte aux fichiers journaux ou la non collision de lignes aux tables de base de données), auquel cas le même soin dans les demandes des clients n'est pas nécessaire. .

Comme RFC spécifie que le correctif contient des "changements généraux" à la ressource, nous devons regarder au-delà du remplacement de champ typique. Si la ressource est pour un compteur, le patch peut demander son incrément, ce qui n'est clairement pas idempotet.

12
Ivan

PATCH les demandes décrivent un ensemble d'opérations à appliquer à une ressource, si vous appliquez deux fois le même ensemble d'opérations à la même ressource, le résultat peut ne pas être le même. C'est à vous de définir les opérations. En d'autres termes, vous devez définir les règles de fusion .

N'oubliez pas qu'une demande PATCH peut être utilisée pour patcher des ressources dans de nombreux formats différents, pas seulement JSON.

Ainsi, une demande PATCH peut être idempotente si vous définissez les règles de fusion comme idempotentes .

Exemple idempotent:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  age: 33
}

// New resource
{
  name: 'Tito',
  age: 33
}

Exemple non idempotent:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  $increment: 'age'
}

// New resource
{
  name: 'Tito',
  age: 33
}

Dans le deuxième exemple, j'ai utilisé une syntaxe "Mongo like" que j'ai inventée pour incrémenter un attribut. De toute évidence, ce n'est pas idempotent, car l'envoi de la même demande plusieurs fois entraînerait des résultats différents à chaque fois.

Maintenant, vous vous demandez peut-être si l'utilisation d'une telle syntaxe inventée est valide. Selon normes , c'est:

La différence entre les demandes PUT et PATCH se reflète dans la façon dont le serveur traite l'entité incluse pour modifier la ressource identifiée par l'URI de demande. Dans une demande PUT, l'entité incluse est considérée comme une version modifiée de la ressource stockée sur le serveur d'origine et le client demande que la version stockée soit remplacée. Avec PATCH, cependant, l'entité jointe contient un ensemble d'instructions décrivant comment une ressource résidant actuellement sur le serveur d'origine doit être modifiée pour produire une nouvelle version.

Et vous vous demandez peut-être aussi s'il est reposant d'utiliser les requêtes PATCH de cette façon, et beaucoup de gens considèrent qu'elles ne le sont pas, voici un bonne réponse avec beaucoup de commentaires sur le problème.

4
Jbm