está usando um PUT com efeitos colaterais aceitáveis ​​(REST)

9

Quero criar um histórico de desfazer sempre que o usuário atualizar um formulário. Por ser uma atualização, desejo usar uma solicitação PUT. No entanto, li que o PUT não precisa ter efeitos colaterais .

É aceitável usar PUT aqui? Existem alternativas melhores?

PUT /person/F02E395A235

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

No servidor

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

Editar:

O histórico ficará visível para o usuário, pois a chamada várias vezes resultaria em várias versões.

A solução foi verificar se a versão era exclusiva antes de criá-la.

roo2
fonte

Respostas:

10

As pessoas que desenhavam o HTTP / 2 eram muito mais detalhadas sobre suas idéias sobre o que o HTTP deveria fazer, mantendo o antigo significado. Vamos ver o que a versão preliminar do HTTP / 2 tem a dizer sobre a idempotência:

4.2.2 Métodos Idempotentes

Um método de solicitação é considerado "idempotente" se o efeito pretendido no servidor de várias solicitações idênticas com esse método for o mesmo que o efeito de uma única solicitação. Dos métodos de solicitação definidos por esta especificação, PUT, DELETE e solicitação segura métodos são idempotentes.

Como a definição de seguro, a propriedade idempotent se aplica apenas ao que foi solicitado pelo usuário; um servidor é livre para registrar cada solicitação separadamente, manter um histórico de controle de revisão ou implementar outros efeitos colaterais não idempotentes para cada solicitação idempotente .

O efeito pretendido no servidor para cada solicitação PUT é atualizar o recurso identificado por esse URI . É exatamente o que acontece no seu caso.

O fato de você decidir versão dos recursos não importa aqui. Se você não deseja criar uma nova versão quando nada foi alterado, precisará comparar a carga útil na solicitação PUT com a versão mais recente (ou identificada de outra forma) do recurso e quando nenhuma das propriedades foi alterada você pode optar por não criar uma nova versão .


Sua edição:

O histórico ficará visível para o usuário, pois várias chamadas resultariam em várias versões

No que diz respeito ao recurso, isso não é efeito colateral . O recurso nesse URI não muda (as mesmas propriedades são PUT). O histórico é apenas metadado, pois provavelmente é solicitado por um URI diferente ou com cabeçalhos de solicitação diferentes.

CodeCaster
fonte
Exceptuam porque você responder a minha problema específico: "é aceitável para PUT para criar um usuário história visível", e me dar uma solução, graças
roo2
Para que problema isso é uma solução? Que a timepropriedade é atualizada? Eu acho que também são metadados, mesmo que estejam no recurso.
CodeCaster
11
O problema era que, se várias PUTs fossem enviadas, o usuário obteria um longo histórico de desfazer com informações redundantes. a verificação de exclusividade resolve isso
roo2
12

O HTTP distingue entre duas propriedades:

  • Idempotência
  • Segurança

Idempotência é definida pelas especificações da seguinte maneira:

Os métodos também podem ter a propriedade " idempotência ", pois (além de problemas de erro ou expiração) os efeitos colaterais de N> 0 pedidos idênticos são os mesmos que para um único pedido. Os métodos GET, HEAD, PUTe DELETEcompartilhar essa propriedade. Além disso, os métodos OPTIONSe TRACE não devem ter efeitos colaterais, e por isso são inerentemente idempotentes.

E segurança:

Em particular, foi estabelecida a convenção de que os métodos GETe NÃO DEVEM ter o significado de tomar uma ação diferente da recuperação. Esses métodos devem ser considerados " seguros ". Isso permite que os agentes do usuário representem outros métodos, como , e , de uma maneira especial, para que o usuário seja informado do fato de que uma ação possivelmente insegura está sendo solicitada.HEADPOSTPUTDELETE

Naturalmente, não é possível garantir que o servidor não gere efeitos colaterais como resultado da execução de uma GETsolicitação; de fato, alguns recursos dinâmicos consideram isso um recurso. A distinção importante aqui é que o usuário não solicitou os efeitos colaterais, portanto, não pode ser responsabilizado por eles.

Observe que a segurança implica idempotência: se um método não tiver efeitos colaterais, sua execução múltipla resultará no mesmo efeito colateral que uma vez, a saber nenhum.

Isso coloca os métodos em três categorias:

  • seguro (e, portanto, também idempotent): GET, HEAD, OPTION,TRACE
  • idempotentes mas não necessariamente seguro: PUT,DELETE
  • nem idempotente nem seguro: POST

O PUT não precisa ter efeitos colaterais.

Isso esta errado. PUTé idempotente, mas não seguro. O ponto inteiro de PUTé ter um efeito colateral, ou seja, atualizar um recurso. O que a idempotência significa é que atualizar o mesmo recurso com o mesmo conteúdo várias vezes deve ter o mesmo efeito que atualizá-lo apenas uma vez.

Observe o último parágrafo da seção sobre segurança [ênfase minha]:

Naturalmente, não é possível garantir que o servidor não gere efeitos colaterais como resultado da execução de uma GETsolicitação; de fato, alguns recursos dinâmicos consideram isso um recurso. A distinção importante aqui é que o usuário não solicitou os efeitos colaterais, portanto, não pode ser responsabilizado por eles .

Embora essa sentença fale sobre GETsegurança, podemos assumir que os autores também pretendiam aplicar o mesmo raciocínio PUTe idempotência. IOW: PUTdeve ter apenas um efeito colateral visível ao usuário , ou seja, atualizar o recurso nomeado. Ele pode ter outros efeitos colaterais, mas o usuário não pode ser responsabilizado por eles.

Por exemplo, o fato de PUTser idempotente significa que posso tentar novamente quantas vezes quiser: a especificação garante que executá-lo várias vezes será exatamente o mesmo que executá-lo uma vez. É perfeitamente válido criar um acúmulo de revisões antigas como efeito colateral dessas várias PUTsolicitações. No entanto, se, como resultado de várias tentativas, seu banco de dados for preenchido com uma lista de pendências de revisões antigas, isso não é problema meu, é seu.

IOW: você pode ter quantos efeitos colaterais quiser, mas

  1. deve olhar para o usuário como se seus pedidos fossem idempotentes
  2. você é responsável por esses efeitos colaterais, não o usuário
Jörg W Mittag
fonte
Sim, idempotência refere-se ao estado do recurso que está sendo colocado, não a qualquer outro estado de servidor / serviço afetado pelo ato da PUT.
Marjan Venema
Voto positivo
Ótima explicação. No entanto, você faz várias declarações como esta: "O objetivo principal do PUT é ter um efeito colateral, ou seja, atualizar um recurso". Isso parece uma contradição, a menos que você queira dizer algo diferente pelo termo "efeito colateral" do que "algo secundário ou não intencional que acontece além do efeito primário pretendido".
MarredCheese
@ MarredCheese: Estou usando o termo em seu significado de programação padrão, que basicamente significa "qualquer 'resultado' que não seja o valor de retorno".
Jörg W Mittag
Ah, claro. Obrigado pelo esclarecimento.
MarredCheese
1

Você está certo de que o PUT não precisa ter efeitos colaterais , no entanto, gostaria de acrescentar algo a isso.

PUT não precisa ter efeitos colaterais no recurso para o qual essa operação PUT está sendo executada

Você está atualizando um personrecurso identificado como F02E395A235, portanto, usar PUT está correto. Agora, como regra comercial, você também acompanha as alterações que são invisíveis para a entidade que chama (consumidor do serviço REST). Isso não adicionará um novo item no personrecurso. O instantâneo histórico não estará acessível usando o /person/terminal. Então, acredito que o PUT deve ser perfeitamente aceitável neste caso.

Aziz Shaikh
fonte
11
Nenhum efeito colateral no recurso sendo colocado, mas qualquer número de efeitos colaterais em outros itens (contadores, registros, rastreios de auditoria, ...) são perfeitamente aceitáveis.
Marjan Venema