Perché il metodo PATCH non è idempotente?


48

Mi chiedevo questo.

Supponiamo che io abbia una userrisorsa con ide namecampi. Se voglio aggiornare un campo potrei semplicemente fare una richiesta PATCH alla risorsa in questo modo

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

E quindi l'applicazione aggiornerà il nome dell'utente 42.

Ma perché se ripeto questa richiesta il risultato sarebbe diverso?

Secondo RFC 5789

PATCH non è né sicuro né idempotente


e se tra invocazioni qualcun altro fa una richiesta di aggiornamento dell'utente 42{"name": "bendjamin franklin"}
moscerino

@gnat non ha un argomento simile anche per il metodo PUT che è invece considerato idempotente? (vedi goo.gl/t24ZSJ )
mattecapu,

"PUT ha una semantica idempotente e quindi può essere tranquillamente utilizzato per aggiornamenti assoluti (ovvero inviamo l'intero stato della risorsa al server), ma non anche per aggiornamenti relativi (ovvero inviamo solo modifiche allo stato della risorsa) , poiché ciò violerebbe la sua semantica ... "( richieste POST e PUT - è solo la convenzione? )
moscerino

1
Ovviamente ... Ma potresti dire che PUT non è idempotente perché tra due richieste uguali un secondo client potrebbe fare una terza richiesta tra i due Ma poiché non ci importa dei dati precedenti, non è un problema. Lo stesso argomento vale per le richieste PATCH.
Mattecapu,

2
Mi sono preso la libertà di aggiungere un riferimento alla specifica pertinente, poiché ritengo che sia altamente pertinente nel contesto di questa domanda.
Pete,

Risposte:


34

Una richiesta PATCH può essere idempotente, ma non è necessario che lo sia. Questo è il motivo per cui è caratterizzato come non idempotente.

Il fatto che PATCH possa essere idempotente o meno dipende fortemente dal modo in cui vengono comunicate le modifiche richieste.
Ad esempio, se il formato della patch è sotto forma di {change: 'Name' from: 'benjamin franklin' to: 'john doe'}, allora qualsiasi richiesta PATCH dopo la prima avrebbe un effetto diverso (una risposta di errore) rispetto alla prima richiesta.
Un altro motivo di non idempotenza può essere che l'applicazione della modifica su qualcos'altro rispetto alla risorsa originale può rendere la risorsa non valida. Questo sarebbe anche il caso se si applica la modifica più volte.


3
Non capisco l'ultimo paragrafo, puoi fare un esempio di come "l'applicazione della modifica su qualcos'altro rispetto alla risorsa originale può rendere la risorsa non valida" e come ciò si riferisce all'applicazione di una modifica più volte alla stessa risorsa?
Robin Green,

3
@RobinGreen: supponiamo che la risorsa sia rappresentata in XML con il requisito che ci sia al massimo un <name>elemento. Se il PATCH aggiunge un <name>elemento a una risorsa che originariamente non ne conteneva uno, quindi applicare il PATCH due volte (o applicarlo a una risorsa che già contiene a <name>) rende la risorsa non valida, perché conterrebbe improvvisamente due <name>elementi che non sono consentiti per tali risorse.
Bart van Ingen Schenau,

13
Il primo esempio che hai fornito non è rilevante in quanto è idempotente. Esempio con DELETE che è idempotente, prima richiesta: la risorsa esiste ma è stata eliminata (restituisce 2xx), seconda richiesta: la risorsa non esiste e continua a non esistere dopo la richiesta, restituisce 4xx. Lo stato del server non è cambiato, quindi l'idempotenza. Nel tuo esempio, prima richiesta: PATCH da BenFra a JohDoe, il nome della risorsa era BenFra ma ora è JohDoe (restituisce 2xx), seconda richiesta: PATCH da BenFra a JohDoe, il nome della risorsa era JohDoe ed è ancora JohDoe (restituisce 4xx). Quindi questo non mostra che PATCH può essere non indipendente.
sp00m,

Maggiori dettagli qui: stackoverflow.com/q/4088350/1225328
sp00m

8

Penso che una risposta chiara quando PATCH in non idempotente sia questo paragrafo di RFC 5789:

Ci sono anche casi in cui i formati di patch non devono operare da un punto base noto (ad es. Aggiunta di righe di testo ai file di registro o righe non collidenti a tabelle di database), nel qual caso non è necessaria la stessa cura nelle richieste del client .

Poiché RFC specifica che la patch contiene alcune "modifiche generali" alla risorsa, dovremmo guardare oltre la tipica sostituzione del campo. Se la risorsa è per un contatore, la patch può richiederne l'incremento, che chiaramente non è idempotet.


2

PATCHle richieste descrivono un insieme di operazioni da applicare a una risorsa, se si applica lo stesso insieme di operazioni due volte alla stessa risorsa, il risultato potrebbe non essere lo stesso. Questo perché la definizione delle operazioni dipende da te. In altre parole, devi definire le regole di fusione .

Ricorda che una PATCHrichiesta potrebbe essere utilizzata per applicare patch alle risorse in molti formati diversi, non solo JSON.

Quindi una PATCHrichiesta può essere idempotente se si definiscono le regole di fusione come idempotenti .

Esempio idempotente:

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

// PATCH request
{
  age: 33
}

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

Esempio non idempotente:

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

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

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

Nel secondo esempio ho usato una sintassi "Mongo like" che ho inventato per incrementare un attributo. Chiaramente questo non è idempotente, poiché l'invio della stessa richiesta più volte comporterebbe risultati diversi ogni volta.

Ora ti starai chiedendo se l'uso di tale sintassi inventata è valido. Secondo gli standard , è:

La differenza tra le richieste PUT e PATCH si riflette nel modo in cui il server elabora l'entità inclusa per modificare la risorsa identificata dall'URI di richiesta. In una richiesta PUT, l'entità inclusa viene considerata una versione modificata della risorsa memorizzata sul server di origine e il client richiede la sostituzione della versione archiviata. Con PATCH, tuttavia, l'entità racchiusa contiene una serie di istruzioni che descrivono come modificare una risorsa attualmente residente sul server di origine per produrre una nuova versione.

E potresti anche chiederti se è riposante utilizzare le PATCHrichieste in questo modo, e molte persone ritengono che non lo siano, ecco una buona risposta con molti commenti sul problema.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.