Por que o método PATCH não é idempotente?

48

Eu estava pensando sobre isso.

Suponha que eu tenha um userrecurso com ide namecampos. Se eu quiser atualizar um campo, poderia fazer uma solicitação PATCH para o recurso como este

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

E então o aplicativo atualizará o nome do usuário 42.

Mas por que, se eu repetir essa solicitação, o resultado seria diferente?

De acordo com a RFC 5789

PATCH não é seguro nem idempotente

mattecapu
fonte
E se entre as chamadas de alguém faz um pedido ao utilizador update 42{"name": "bendjamin franklin"}
mosquito
@gnat também não é válido para o método PUT, que é considerado idempotente? (veja goo.gl/t24ZSJ )
mattecapu
"O PUT possui semântica idempotente e, portanto, pode ser usado com segurança para atualizações absolutas (ou seja, enviamos todo o estado do recurso para o servidor), mas não também para atualizações relativas (ou seja, enviamos apenas alterações no estado do recurso) , pois isso violaria sua semântica ... "( solicitações POST e PUT - isso é apenas a convenção? ) #
306
1
Obviamente ... Mas você poderia dizer que PUT não é idempotente porque, entre duas solicitações iguais, um segundo cliente pode fazer uma terceira solicitação entre as duas. Mas, como não nos importamos com dados anteriores, isso não é um problema. O mesmo argumento vale para solicitações PATCH.
mattecapu
2
Tomei a liberdade de adicionar uma referência à especificação relevante, pois acredito que é altamente relevante no contexto desta questão.
Pete

Respostas:

34

Uma solicitação PATCH pode ser idempotente, mas não é necessária. Essa é a razão pela qual é caracterizada como não-idempotente.

Se PATCH pode ser idempotente ou não depende muito de como as alterações necessárias são comunicadas.
Por exemplo, se o formato do patch estiver na forma de {change: 'Name' from: 'benjamin franklin' to: 'john doe'}, qualquer solicitação PATCH após a primeira terá um efeito diferente (uma resposta de falha) que a primeira solicitação.
Outro motivo para a não idempotência pode ser que a aplicação da modificação em algo que não seja o recurso original pode tornar o recurso inválido. Esse também seria o caso se você aplicar a alteração várias vezes.

Bart van Ingen Schenau
fonte
3
Não entendo o último parágrafo, você pode dar um exemplo de como "aplicar a modificação em algo que não seja o recurso original pode tornar o recurso inválido" e como isso se relaciona com a aplicação de uma alteração várias vezes no mesmo recurso?
Robin Green
3
@RobinGreen: Suponha que o recurso esteja representado em XML com o requisito de que exista no máximo um <name>elemento. Se o PATCH adicionar um <name>elemento a um recurso que originalmente não continha um, aplicar o PATCH duas vezes (ou aplicá-lo a um recurso que já contenha a <name>) torna o recurso inválido, porque subitamente conteria dois <name>elementos que não são permitidos para esses recursos.
Bart van Ingen Schenau 12/08/2015
13
O primeiro exemplo que você deu não é IMHO relevante, pois é idempotente. Exemplo com DELETE que é idempotente, primeira solicitação: o recurso existia mas foi excluído (retorna 2xx), segunda solicitação: o recurso não existe e ainda não existe após a solicitação, retorna 4xx. O estado do servidor não mudou, portanto, a idempotência. No seu exemplo, primeira solicitação: PATCH de BenFra para JohDoe, o nome do recurso era BenFra, mas agora é JohDoe (retorna 2xx), segunda solicitação: PATCH de BenFra para JohDoe, o nome do recurso era JohDoe e ainda é JohDoe (retorna 4xx). Portanto, isso não mostra que PATCH pode ser não-potencial.
Sp00m
Mais detalhes aqui: stackoverflow.com/q/4088350/1225328
sp00m
8

Penso que uma resposta clara quando PATCH não é idempotente é este parágrafo da RFC 5789:

Também existem casos em que os formatos de correção não precisam operar a partir de um ponto de base conhecido (por exemplo, anexando linhas de texto aos arquivos de log ou linhas que não colidem nas tabelas do banco de dados); nesse caso, o mesmo cuidado nas solicitações do cliente não é necessário .

Como o RFC especifica que o patch contém algumas "alterações gerais" no recurso, devemos olhar além da substituição típica de campo. Se o recurso é para um contador, o patch pode solicitar seu incremento, o que claramente não é idempotet.

Ivan
fonte
2

PATCHOs pedidos descrevem um conjunto de operações a serem aplicadas a um recurso. Se você aplicar o mesmo conjunto de operações duas vezes ao mesmo recurso, o resultado poderá não ser o mesmo. Isso ocorre porque a definição das operações depende de você. Em outras palavras, você precisa definir as regras de mesclagem .

Lembre-se de que uma PATCHsolicitação pode ser usada para corrigir recursos em vários formatos diferentes, não apenas no JSON.

Portanto, uma PATCHsolicitação pode ser idempotente se você definir as regras de mesclagem como idempotentes .

Exemplo idêntico:

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

// PATCH request
{
  age: 33
}

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

Exemplo não idempotente:

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

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

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

No segundo exemplo, usei uma sintaxe "tipo Mongo" que inventei para incrementar um atributo. Claramente, isso não é idempotente, pois o envio da mesma solicitação várias vezes resultaria em resultados diferentes a cada vez.

Agora você pode estar se perguntando se o uso de uma sintaxe inventada é válida. De acordo com os padrões , é:

A diferença entre as solicitações PUT e PATCH é refletida na maneira como o servidor processa a entidade fechada para modificar o recurso identificado pelo Request-URI. Em uma solicitação PUT, a entidade incluída é considerada uma versão modificada do recurso armazenado no servidor de origem e o cliente está solicitando que a versão armazenada seja substituída. Com PATCH, no entanto, a entidade incluída contém um conjunto de instruções que descrevem como um recurso que atualmente reside no servidor de origem deve ser modificado para produzir uma nova versão.

E você também pode estar se perguntando se é tranqüilo usar PATCHsolicitações dessa maneira e, como muitas pessoas consideram que não são, aqui está uma boa resposta com muitos comentários sobre o problema.

Jbm
fonte