Elimina più record utilizzando REST


97

Qual è il modo REST per eliminare più elementi?

Il mio caso d'uso è che ho una collezione Backbone in cui devo essere in grado di eliminare più elementi contemporaneamente. Le opzioni sembrano essere:

  1. Invia una richiesta DELETE per ogni singolo record (che sembra una cattiva idea se ci sono potenzialmente dozzine di elementi);
  2. Invia un DELETE in cui gli ID da eliminare sono raggruppati nell'URL (ad esempio, "/ records / 1; 2; 3");
  3. In un modo non REST, invia un oggetto JSON personalizzato contenente gli ID contrassegnati per l'eliminazione.

Tutte le opzioni sono tutt'altro che ideali.

Sembra un'area grigia della convenzione REST.


Risposte:


92
  1. È una valida scelta RESTful, ma ovviamente ha i limiti che hai descritto.
  2. Non farlo. Sarebbe interpretato dagli intermediari nel senso di "CANCELLARE la (singola) risorsa in /records/1;2;3" - Quindi una risposta 2xx a questo potrebbe indurli a svuotare la cache di /records/1;2;3; non eliminare /records/1, /records/2o /records/3; proxy una risposta 410 per /records/1;2;3, o altre cose che non hanno senso dal tuo punto di vista.
  3. Questa scelta è la migliore e può essere eseguita RESTfully. Se stai creando un'API e desideri consentire modifiche di massa alle risorse, puoi utilizzare REST per farlo, ma esattamente come non è immediatamente ovvio per molti. Un metodo consiste nel creare una risorsa di 'richiesta di modifica' (ad esempio inserendo un corpo come records=[1,2,3]a /delete-requests) e interrogare la risorsa creata (specificata dall'intestazione Locationdella risposta) per scoprire se la tua richiesta è stata accettata, rifiutata, è in corso o ha completato. Ciò è utile per operazioni di lunga durata. Un altro modo è inviare una PATCHrichiesta alla risorsa elenco ,/records, il cui corpo contiene un elenco di risorse e azioni da eseguire su tali risorse (in qualsiasi formato si desideri supportare). Questo è utile per operazioni veloci dove il codice di risposta alla richiesta può indicare l'esito dell'operazione.

Tutto può essere ottenuto rispettando i vincoli di REST, e di solito la risposta è trasformare il "problema" in una risorsa e dargli un URL.
Pertanto, le operazioni batch, come eliminare qui o POST di più elementi in un elenco o apportare la stessa modifica a una serie di risorse, possono essere gestite creando un elenco di "operazioni batch" e inserendo la nuova operazione su di esso.

Non dimenticare, REST non è l'unico modo per risolvere qualsiasi problema. “Riposo” è solo uno stile architettonico e non si hanno ad aderire ad essa (ma si perde alcuni vantaggi di Internet, se non si fa). Ti suggerisco di guardare questo elenco di architetture API HTTP e scegliere quella che fa per te. Renditi consapevole di ciò che perdi se scegli un'altra architettura e prendi una decisione informata in base al tuo caso d'uso.

Ci sono alcune risposte negative a questa domanda sui modelli per la gestione delle operazioni batch nei servizi Web REST? che hanno troppi voti positivi, ma dovrebbero anche essere letti.


2
Non è il tuo server di cui ti devi preoccupare, sono intermediari, CDN, proxy di cache, ecc. Internet è un sistema a più livelli. Questo è il motivo per cui funziona così bene. Roy ha determinato quali aspetti del sistema erano necessari per il suo successo e li ha chiamati REST. Se invii una DELETErichiesta, qualunque cosa si trovi tra il richiedente e il server penserà che una singola risorsa, all'URL specificato, venga eliminata. Le stringhe di query sono parti opache dell'URL di questi dispositivi, quindi non importa come specifichi la tua API, non sono a conoscenza di questa conoscenza, quindi non possono comportarsi diversamente.
Nicholas Shanks

3
/ records / 1; 2; 3 non funzionerà se hai molte risorse da eliminare a causa di restrizioni sulla lunghezza dell'URI
dukethrash

3
Si noti che se si considera DELETE e un ente che definisce le risorse da eliminare, alcuni intermediari potrebbero non inoltrare l'ente. Inoltre, alcuni client HTTP non possono aggiungere un corpo a un DELETE. Vedere stackoverflow.com/questions/299628/...
Luca Puplett

3
@ LukePuplett Vorrei semplicemente affermare che il passaggio di un corpo di richiesta con una DELETErichiesta è vietato. Non farlo. Se lo fai mangerò i tuoi figli. Nom nom nom.
Nicholas Shanks

3
Il problema con l'argomento per # 3 è che comporta la stessa penalità del controargomento contro # 2. La creazione di una risorsa da eliminare non è qualcosa che i proxy upstream sapranno come gestire: lo stesso controargomento sollevato contro l'approccio n. 2.
LB2

16

Se GET /records?filteringCriteriarestituisce un array di tutti i record che corrispondono ai criteri, DELETE /records?filteringCriteriapotrebbe eliminare tutti questi record.

In questo caso la risposta alla tua domanda sarebbe DELETE /records?id=1&id=2&id=3.


1
Sono anche giunto a questa conclusione: basta capovolgere il verbo in quello che vuoi fare. Non capisco come ciò che va per GET non va per DELETE.
Luke Puplett

9
GET /records?id=1&id=2&id=3non non significa “ottenere i tre record con ID 1, 2 e 3”, significa “ottenere la singola risorsa con il sentiero URL / record? id = 1 & id = 2 & id = 3”, che potrebbe essere una foto di una rapa, un testo semplice documento contenente il numero "42" in cinese, o potrebbe non esistere.
Nicholas Shanks

Considera quanto segue: due richieste sequenziali per /records?id=1e /records?id=2vengono inviate e le loro risposte memorizzate nella cache da qualche intermediario (ad esempio il tuo browser o ISP). Se Internet sapeva cosa intendeva la tua applicazione con questo, è ovvio che una richiesta di /records?id=1&id=2potrebbe essere restituita dalla cache semplicemente unendo (in qualche modo) i due risultati che ha già, senza dover chiedere al server di origine. Ma questo non è possibile. /records?id=1&id=2potrebbe non essere valido (è consentito solo 1 ID per richiesta) o potrebbe restituire qualcosa di completamente diverso (una rapa).
Nicholas Shanks

Questo è un problema di base della memorizzazione nella cache delle risorse. Se il mio DBA ha modificato direttamente lo stato, le cache ora non sono sincronizzate. Fornisci un esempio 410 restituito dall'intermediario, ma 410 è per le rimozioni permanenti, dopo ELIMINA una cache potrebbe cancellare il suo slot per quell'URL, ma non invierà un 410 o un 404, poiché non sa se un DBA non ha semplicemente rimesso immediatamente la risorsa all'origine.
Luke Puplett

4
@NicholasShanks Sono davvero in disaccordo. Se i risultati vengono memorizzati nella cache, è colpa del server. E se stai parlando del design dell'API, si spera che tu sia quello che scrive il codice per il server. Sia che si utilizzi id[]=1&id[]=2o id=1&id=2nella stringa di query per rappresentare una matrice di valori, quella stringa di query rappresenta proprio questo. E penso che sia estremamente comune e buona pratica fare in modo che la stringa di query rappresenti un filtro. Inoltre, se consenti eliminazioni e aggiornamenti, non memorizzare le GETrichieste nella cache . Se lo fai, i client manterranno lo stato stantio.
Joseph Nields,

8

Penso che l'API SyncStorage v1.5 di Mozilla Storage Service sia un buon modo per eliminare più record utilizzando REST.

Elimina un'intera raccolta.

DELETE https://<endpoint-url>/storage/<collection>

Elimina più BSO da una raccolta con una singola richiesta.

DELETE https://<endpoint-url>/storage/<collection>?ids=<ids>

ids : elimina i BSO dalla raccolta i cui ID si trovano nell'elenco separato da virgole fornito. È possibile fornire un massimo di 100 ID.

Elimina il BSO nella posizione specificata.

DELETE https://<endpoint-url>/storage/<collection>/<id>

http://moz-services-docs.readthedocs.io/en/latest/storage/apis-1.5.html#api-instructions


Questa sembra una buona soluzione. Immagino che se Mozilla pensa che sia corretto, allora deve essere? L'unica domanda è quindi la gestione degli errori. Supponiamo che passino? Ids = 1,2,3 e id 3 non esiste, elimini 1 e 2 quindi rispondi con un 200 perché il richiedente vuole che 3 sia andato e non c'è quindi non importa? o se sono autorizzati a cancellare 1 ma non 2 ... non elimini nulla e rispondi con un errore o elimini ciò che puoi e lasci gli altri ...
tempcke

In genere restituisco una risposta positiva perché lo stato finale è lo stesso indipendentemente. Ciò semplifica anche la logica sul client poiché non devono più gestire quello stato di errore. Per quanto riguarda il caso di autorizzazione, fallirei l'intera richiesta ... ma in realtà dipende dal tuo caso d'uso.
Nathan Phetteplace,

3

Sembra un'area grigia della convenzione REST.

Sì, finora ho trovato solo una guida alla progettazione dell'API REST che menziona le operazioni batch (come l'eliminazione in batch): la guida alla progettazione delle API di Google .

Questa guida menziona la creazione di metodi "personalizzati" che possono essere associati tramite una risorsa utilizzando i due punti, ad esempio https://service.name/v1/some/resource/name:customVerb, menziona anche esplicitamente le operazioni batch come caso d'uso:

Un metodo personalizzato può essere associato a una risorsa, una raccolta o un servizio. Può richiedere una richiesta arbitraria e restituire una risposta arbitraria e supporta anche richieste e risposte in streaming. [...] I metodi personalizzati dovrebbero utilizzare il verbo HTTP POST poiché ha la semantica più flessibile [...] Per i metodi critici per le prestazioni, può essere utile fornire metodi batch personalizzati per ridurre l'overhead per richiesta .

Quindi potresti fare quanto segue secondo la guida api di Google:

POST /api/path/to/your/collection:batchDelete

... per eliminare una serie di elementi della risorsa della raccolta.


È una soluzione praticabile che l'elenco di elementi venga comunicato tramite un array formattato JSON?
Daniele

si certo. puoi POST un payload in cui gli ID vengono inviati tramite un array json.
B12Toaster

È interessante che la guida API di Google abbia detto If the HTTP verb used for the custom method does not accept an HTTP request body (GET, DELETE), the HTTP configuration of such method must not use the body clause at all,nel capitolo Metodo personalizzato. Ma l' GET accounts.locations.batchGetapi è il metodo GET con il corpo. È strano. developers.google.com/my-business/reference/rest/v4/…
鄭元傑

@ 鄭元傑 d'accordo, sembra un po 'strano a prima vista ma se guardi da vicino è in realtà un POSTmetodo http utilizzato e viene nominato solo il metodo personalizzato batchGet. Immagino che Google lo faccia per (a) attenersi alla regola che tutti i metodi personalizzati devono essere POST(vedi la mia risposta) e (b) per rendere più facile per le persone mettere un "filtro" nel corpo in modo da non doverlo fare tu esci o codifica il filtro come con le stringhe di query. lo svantaggio, ovviamente, è che non è più memorizzabile nella cache ...
B12Toaster

https://service.name/v1/some/resource/name:customVerbnon è RESTful per definizione.
deamon

2

Ho consentito la sostituzione all'ingrosso di una collezione, ad esempio PUT ~/people/123/shoesdove il corpo è l'intera rappresentazione della collezione.

Questo funziona per piccole raccolte figlio di elementi in cui il client desidera rivedere gli elementi ed eliminarne alcuni e aggiungerne altri e quindi aggiornare il server. Potrebbero Mettere una raccolta vuota per eliminarli tutti.

Ciò significherebbe che GET ~/people/123/shoes/9rimarrebbe ancora nella cache anche se un PUT lo ha eliminato, ma questo è solo un problema di cache e sarebbe un problema se qualcun altro eliminasse la scarpa.

Le mie API di dati / sistemi utilizzano sempre ETag al contrario dei tempi di scadenza, quindi il server viene colpito a ogni richiesta e ho bisogno di intestazioni di versione / concorrenza corrette per modificare i dati. Per le API di sola lettura e allineate a visualizzazione / rapporto, utilizzo i tempi di scadenza per ridurre gli hit all'origine, ad esempio una classifica può essere valida per 10 minuti.

Per raccolte molto più grandi, ad esempio ~/people, tendo a non aver bisogno di più eliminazioni, il caso d'uso tende a non sorgere naturalmente e quindi ELIMINA singola funziona bene.

In futuro, e dall'esperienza con la creazione di API REST e con gli stessi problemi e requisiti, come l'audit, sarei propenso a utilizzare solo i verbi GET e POST e progettare attorno agli eventi, ad esempio POST un evento di cambio di indirizzo, anche se sospetto che arriverà con la sua serie di problemi :)

Consentirei inoltre agli sviluppatori front-end di creare le proprie API che utilizzano API back-end più rigide poiché spesso ci sono ragioni pratiche e valide sul lato client per cui non amano i rigidi progetti di API REST "fanatici del campo" e per la produttività e motivi di stratificazione della cache.


Ho adorato questa risposta fino a quando non ho letto l'ultima frase :) Non ho mai visto un caso d'uso in cui l'applicazione di REST rigoroso ha avuto un netto effetto dannoso. Certo, può creare più codice da scrivere su entrambe le estremità, ma si ottiene un sistema più sicuro, più pulito e meno accoppiato.
Nicholas Shanks

Haha. In realtà è diventato uno schema! Il backend per il front-end è chiamato radar della tecnologia ThoughtWorks. Consente inoltre di scrivere più logica dell'applicazione che sarebbe ingombrante, ad esempio, JavaScript e ovviamente può essere aggiornata senza un client, quindi aggiorna, ad esempio, per un'app iOS.
Luke Puplett

Leggendo le prime quattro hit di Google, sembra che questa tecnica di BFF possa funzionare solo quando i clienti sono sotto il tuo controllo . Gli sviluppatori client sviluppano l'API che desiderano, mappando le chiamate alle API dei microservizi che sono il vero back-end. In questo diagramma: samnewman.io/patterns/architectural/bff/#bff metterei la linea "Perimeter" sotto le caselle BFF - ogni casella è semplicemente parte del client. Potrebbe anche vivere al di fuori del data center che ospita i microservizi. Inoltre, non vedo come REST non si applichi a entrambe le interfacce (client / BFF e BFF / microservizio).
Nicholas Shanks

1
Sì, questo è un buon punto. Di solito è per quando hai un team building microservizi e un team che crea un'app angolare, ad esempio, e quel team di sviluppo è più tipi di front-end a cui non piace dover lavorare contro un mucchio di piccoli servizi puristi. Anche se non vedo alcun motivo per cui non puoi utilizzare lo stesso modello per astrarre i microservizi e l'aggregazione in una facciata più utilizzabile per i tuoi clienti, in modo tale che i microservizi possano essere modificati senza influire sulla facciata.
Luke Puplett

Un endpoint API dovrebbe modellare le esigenze del dominio e dell'azienda. Codice per risolvere questi problemi ed evitare un'ingegnerizzazione eccessiva per aderire a specifiche rigide e inflessibili molte volte. REST comunque non è altro che linee guida.
Victorio Berra
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.