Come gestire "Blocco Ottimistico" in una raccolta con intestazioni ETag?

1

Considera endpoint /projects che restituisce un elenco di progetti con le seguenti intestazioni:

HTTP/1.1 200 OK
Etag: "superEtag"

Il valore etag rappresenta un hash dell'intera raccolta e non consente a un client di aggiornare una singola risorsa, ad es. /projects/1 .

Il recupero delle risorse individualmente non ha senso, quindi come posso gestire il blocco ottimistico con una raccolta?

    
posta maximedupre 05.10.2018 - 01:01
fonte

2 risposte

1

When doing GET /projects, the ETag corresponds to the hash of the collection. Now if I want to do PUT /projects/1, I need the hash of this specific resource for the conditional request (If-Match) to be successful. I could do GET /projects/{id} to get the individual hash for each resource, but it makes no sense; the collection service would become useless.

Penso che il problema sia che HTTP non significa ciò che vuoi che significhi.

Fondamentalmente, la semantica di HTTP è che le risorse sono memorizzate in un archivio di valori chiave piano . Sebbene /collection e /collection/item siano identificatori gerarchici (possiamo usare risoluzione relativa per ottenere da uno a l'altro), le risorse che identificano non sono gerarchiche. Non vi è alcuna relazione dedotta dalla compitazione degli identificatori simile.

Ecco perché DELETE /collection non fa nulla alla tua copia cache locale di /collection/item .

Poiché non esiste una relazione dedotta tra la raccolta e l'elemento, non esiste un vettore generico disponibile per comunicare l'eTag degli articoli nei metadati per la raccolta.

Puoi certamente fare uno dei due

GET /collection
Conditional PUT /collection

GET /collection/item
Conditional PUT /collection/item

e il server di origine può, a sua discrezione, modificare anche la rappresentazione dell'altra risorsa, come effetto collaterale.

Questo non vuol dire che non si possa comunicare l'informazione a mano - non c'è nulla contro le regole sulla restituzione di una rappresentazione della collezione che comunica le rappresentazioni appropriate degli elementi del membro, insieme ai loro validatori, in modo che Il client "intelligente" può creare le richieste corrette senza bisogno di ottenere i singoli elementi.

What do you mean by "the resources that they identify are not hierarchical"?

Disclaimer: tutte le analogie non sono normative; ciò che è reale è ciò che è descritto nelle specifiche.

La semantica delle risorse HTTP non è proprio come quella di un file system. Ad esempio, se emettiamo il seguente comando su linux

rm -rf /collection

quindi uno degli effetti che ci aspettiamo è la rimozione di /collection/item . Ma non è vero per HTTP!

DELETE /collection

non dice nulla sulla risorsa /collection/item . potrebbe essere che quando il server elabora questa richiesta, gli effetti collaterali potrebbero influenzare altre risorse. Ma HTTP non sta descrivendo le implementazioni, sta solo assegnando un significato ai messaggi. Il significato del messaggio di richiesta è limitato solo dalla risorsa di destinazione.

Un altro modo per dire la stessa cosa: per quanto riguarda HTTP, nessuno di questi identificatori è "sbagliato" per un oggetto in una collezione.

/collection/item
/item/collection
/f5add126-65ef-4122-8657-03e672f159c4

Alcuni dei framework del server che utilizziamo per implementare la cura dei nostri server; ad esempio, Rails ha opinioni sull'ortografia . Ma questi sono solo i dettagli di implementazione dietro l'interfaccia uniforme.

Quindi sì, nel tuo modello di dominio le entità di progetto e le entità di tracce possono formare una gerarchia, e potresti scegliere le ortografie per gli identificatori di risorse che riflettono quella gerarchia, ma la semantica di HTTP sono quelle di un piatto archivio valori chiave.

# Example #1: hierarchical key value store

echo ; cat <<EOF | python
d={}
d["/collection"]={}
d["/collection"]["/item"]=456
d.pop("/collection")
print(d)
EOF

{}

# Example #2: flat key value store

echo ; cat <<EOF | python
d={}
d["/collection"]={}
d["/collection/item"]=456
d.pop("/collection")
print(d)
EOF

{'/collection/item': 456}

HTTP si comporta come il secondo esempio.

    
risposta data 17.10.2018 - 23:24
fonte
1

In realtà, sta a te decidere come usare Etag. Va bene se vuoi trattare la risorsa come un albero in cui tutte le foglie sullo stesso ramo hanno lo stesso Etag dell'ETag del ramo.

es. quando fai GET /projects/small/ ottieni ETag: "xyzzy". Quindi quando fai PUT /projects/small/1 usi lo stesso ETag: "xyzzy". Ricordati di aggiornare l'Etag del ramo se una qualsiasi delle foglie viene modificata. Così,

GET /projects/small/ --> ETag: "xyzzy"
PUT /projects/small/1 ETag: "xyzzy" --> OK
PUT /projects/small/2 ETag: "xyzzy" --> Conflict

Il secondo PUT deve fallire perché l'ETag è già stato aggiornato.

Dovrei dire che condividere Etag in questo modo è utile solo se ci sono solo pochi aggiornamenti. Se ti aspetti più di qualche aggiornamento, è meglio restituire i link ai singoli progetti per GET /projects/small/ (invece di tutte le entità sotto quell'URL), quindi il cliente dovrà recuperare la singola entità quando vorrebbe fare un aggiornamento .

    
risposta data 18.10.2018 - 01:26
fonte

Leggi altre domande sui tag