Può "REST senza PUT" supportare il blocco ottimistico usando ETags?

2

Rest senza PUT modelli immutabili, append-only (event-source) ) modifica dello stato favorendo l'invio di nuove risorse di modifica reiterata rispetto agli aggiornamenti PUT-in originali. Esempio: creazione e modifica di un ordine di caffè ...

REST tradizionale:

  • POST / order {type: latte} → 201 Created / order / 1234
  • PUT / order / 1234 {type: mocha} → 200 OK

REST senza PUT:

  • POST / order {type: latte} → 201 Created / order / 1234
  • POST / order / 1234 / change-req {type: mocha} → 201 Created / order / 1234 / change-req / 5678

Domanda: può funzionare con il blocco ottimistico usando Etags e If-Match?

REST tradizionale:

  • POST / order {type: latte} → 201 Created / order / 1234, ETag: "1111"
  • PUT / ordine / 1234 {stato: consegnato} If-Match "1111" → 200 OK ETag "2222" (il barista è veloce!)
  • PUT / order / 1234 {type: mocha} If-Match "1111" → 412 Precondizione fallita

REST senza PUT:

  • POST / order {type: latte} → 201 Created / order / 1234, ETag: "1111"
  • POST / order / 1234 / deliver-req {} If-Match "1111" → 201 Created / order / 1234 / deliver-req / 9012
  • POST / order / 1234 / change-req {type: mocha} If-Match "1111" → 412 Precondizione fallita

Ha senso consentire agli Etags inviati e abbinati di fare riferimento alla risorsa dell'ordine originale, e non allo stato delle risorse modificate (deliver-req, change-req) stesse?

    
posta Anthony Leonard 16.11.2015 - 18:35
fonte

1 risposta

3

Aggiornamento: Can etags + If-Match funziona? Sì, sono sicuro che può essere fatto funzionare. Il tuo cliente dovrà interpretare l'errore 412 come un errore di concorrenza ottimistico. Per quanto riguarda il suo utilizzo con POST, la specifica non limita i metodi è consentito su.

The If-Match request-header field is used with a method to make it conditional.

Vorrei anche restituire 412 (con un messaggio diverso) se non ci sono entità (e quindi nessun etag) trovate nel database. In altre parole, stanno richiedendo modifiche per un'entità che non è mai stata creata.

La questione rimane se utilizzare If-Match per concorrenza ottimistica. Il problema principale è che semanticamente, consente a il client di specificare se la risorsa debba essere aggiornata o meno. È molto probabile che l'azienda desidererà che alcuni ottimistici fallimenti di concorrenza continuino comunque. F.ex. se CancelOrder viene ricevuto, indipendentemente dalla mancata corrispondenza della versione, deve essere elaborato. (Potrebbe essere che l'ordine sia già stato spedito e l'annullamento non riesce, ma almeno possiamo rispondere con quell'informazione invece di un errore di disallineamento della versione!) Questa non è una decisione che di solito desideri sul client. Tuttavia, potresti sovvertire la specifica e utilizzare If-Match per inviare la tua versione (e-tag), e in definitiva lasciare che le regole aziendali decidano se l'operazione dovrebbe continuare se i tag non corrispondono e restituire il 412 in caso contrario.

Dovresti inviare l'etag all'URI reificato? Sì. Infatti, come parte della modellazione di ciò che è essenzialmente messaggistica su HTTP, non dovrebbe esserci alcun URI POST per una "risorsa ordine originale". Cosa stai facendo veramente con quell'URI di ordine sta inviando il messaggio di comando "Crea ordine". Se si cambia il nome per adattarlo, ciò renderebbe molto più chiaro che il POST di una risorsa dell'Ordine non ha senso. In questo tipo di API gli URI POST sono tipi di messaggio, non risorse.

A proposito, sono assolutamente d'accordo con l'articolo collegato a fare questi nomi al posto dei verbi. REST tenta di rappresentare operazioni (azioni) come verbi HTTP, che si adatta bene alle 4 operazioni CRUD, ma è troppo limitato per le operazioni di dominio. Comprendendo ciò, l'autore dell'articolo sposta l'operazione del dominio come parte dell'URI, ma cerca di mantenere il principio REST degli URI del nome (presumo) per attenersi alla specifica REST in lettere, anche se non è seguito nello spirito. A volte devi solo riconoscere che qualcosa non va bene e non forzarlo. I verbi includono in modo definitivo le azioni e le azioni rappresentano più da vicino le operazioni aziendali. Pertanto, utilizza POST /create-customer anziché POST /create-customer-req . Vuoi davvero aggiungere un superfluo -req alla fine di ogni URI?

Il lato di lettura
Ha senso avere un GET URI per l'ordine. In realtà, ha senso avere più URI GET per Ordine, uno per ogni prospettiva diversa (vista) sull'ordine. F.ex. è probabile che un cliente desideri informazioni diverse guardando i propri ordini rispetto al responsabile delle vendite. (Questo può effettivamente portare a diversi contesti limitati, ma questa è una discussione diversa.)

Aggiornamento

Vedo che la modifica ha modificato gli URI nel formato POST order/123/action anziché includere l'ID nel corpo JSON. Ad ogni modo, questo non ha senso nel contesto di REST. L'URI dovrebbe rappresentare una risorsa, ma qui è un tipo di messaggio. Il fatto che stai comunicando un ID tramite URI non ne fa una risorsa. Allo stesso modo che cambiare un'azione in una forma di nome non ne fa una risorsa. Attenersi alle convenzioni di denominazione REST senza implementare effettivamente un'interfaccia uniforme non è in alcun modo utile. L'idea di seguire REST è di usare HTTP in modo standard e coerente in modo che i clienti abbiano una ragionevole aspettativa per come funziona.

Nel caso di una risorsa CRUD conforme a REST, se hai dato al cliente un URI e una forma oggetto, sarebbe già sapere come eseguire tutte le operazioni. Nel tuo caso, i clienti non sono a conoscenza delle tue operazioni personalizzate finché non li dici (tramite hypermedia forse, o hard-coding nel client).

Consentitemi di sottolineare nuovamente: Va bene che il vostro caso d'uso non rientra nella casella REST! Va bene usare HTTP in un modo diverso che ha senso per il tuo sistema!

    
risposta data 16.11.2015 - 20:54
fonte