Quale verbo HTTP dovrei usare per attivare un'azione in un servizio web REST?


81

Sto implementando un servizio web RESTful e una delle azioni disponibili sarà reload. Sarà utilizzato per ricaricare configurazioni, cache, ecc.

Abbiamo iniziato con GETun URI semplice come questo: ${path}/cache/reload(nessun parametro viene passato, viene chiamato solo l'URI). Sono consapevole che i dati non devono essere modificati con una richiesta GET.

Qual è il verbo corretto da usare per invocare un'azione / comando in un servizio Web RESTful?

La ricarica è un comando del servizio web REST che ricarica la propria cache / configurazione / ecc. Non è un metodo che restituisce informazioni al client.

Probabilmente quello che sto cercando di fare non è REST, ma è ancora qualcosa che deve essere fatto in questo modo. Il reloadmetodo era solo un esempio reale che ha un senso nell'ambito di applicazione e la maggior parte delle risposte si concentrava su di esso, ma in realtà, avevo solo bisogno di sapere quale verbo innescare un'azione che non fa CRUD, ma cambia ancora i dati / stato.

Ho trovato questo asnwer dettagliato su Stack Overflow sull'argomento: https://stackoverflow.com/questions/16877968/


1
"Ricarica" ​​è il senso di un'app che aggiorna i dati che verranno visualizzati? C'è qualche differenza tra ricaricare e recuperare nuovamente i dati?
Sean Redmond,

1
@SeanRedmond No, i dati non vengono inviati al client. In effetti, il client sta dicendo al servizio web REST di eseguire e il comando interno (ricaricare). Qualcosa del tipo: "molte configurazioni sono state modificate nel database, quindi il servizio web REST, ricaricalo ora nella memoria".
Renato Dinhani,


Hai preso in considerazione l'utilizzo di un parametro di intestazione su richieste appropriate? Sembra molto un aggiornamento della cache ...
Guran

Risposte:


25

Non credo che esista un verbo appropriato per questa azione perché questa transazione non è realmente "RESTful". La "s" e la "t" indicano "trasferimento di stato" e qui non viene trasferito nulla. Oppure, in altre parole, secondo la definizione più rigorosa, i verbi come PUT e POST sono sempre usati con un nome e "ricaricare" ha solo il verbo.

Questa ricarica potrebbe non essere RESTful, ma potrebbe essere comunque utile e dovrai solo scegliere un modo per farlo e convivere o spiegare che è insolito. OTTENERE è probabilmente il più semplice. C'è una buona dose di scetticismo nei commenti, quindi, dovresti pensare se questa azione di ricarica è necessaria o meno perché qualcos'altro non sta facendo esattamente quello che dovrebbe fare.


Sono d'accordo che questo non è RESTful ma può essere utile. Penso che dovresti consigliare un PUT, perché questo è probabilmente idempotente ma non nullo.
Aaron Greenwald,

@Aaron, il confronto tra idempotente e nullimpotente va benissimo, ma come si determina quando non è impotente?
Craig,

@Craig è idempotente se eseguirlo più volte ha lo stesso effetto di eseguirlo una volta. È nullipotent se eseguirlo una o più volte ha lo stesso effetto sul server di eseguirlo zero volte. en.wikipedia.org/wiki/Idempotence
Aaron Greenwald

5
@AaronGreenwald “notimpotent” [not-im-poht-nt] [not-im-pawr-tnt] - aggettivo - 1. Un gioco di parole, “non importante”, antonimo dell'aggettivo “importante”. 2. Umorismo ... ;-)
Craig

@Craig L'ho perso del tutto :)
Aaron Greenwald il

75

Se vuoi essere RESTful, non pensare al verbo per eseguire un'azione, pensa allo stato in cui vuoi che si trovi la risorsa dopo che il client ha fatto qualcosa.

Quindi, usando uno dei tuoi esempi sopra, hai una coda e-mail che invia e-mail. Vuoi che il client metta quella coda di posta elettronica nello stato di pausa o di arresto o qualcosa del genere.

Quindi il client inserisce un nuovo stato nel server per quella risorsa. Può essere semplice come questo JSON

PUT http://myserver.com/services/email_service HTTP/1.1
Content-Type: text/json

{"status":"paused"}

Il server scopre come passare dallo stato corrente (ad esempio "in esecuzione") allo stato / stato "in pausa".

Se il client esegue un GET sulla risorsa, dovrebbe restituire lo stato in cui si trova attualmente (ad esempio "in pausa").

Il motivo per farlo in questo modo, e perché REST può essere così potente, è che lasci l'HOW per arrivare a quello stato sul server.

Il client dice semplicemente "Questo è lo stato in cui dovresti essere ora" e il server capisce come raggiungerlo. Potrebbe essere un semplice capovolgimento in un database. Potrebbe richiedere migliaia di azioni. Al cliente non importa e non deve saperlo.

Quindi puoi riscrivere / ridisegnare completamente il modo in cui il server lo fa e al client non importa. Il cliente deve solo essere consapevole dei diversi stati (e delle loro rappresentazioni) di una risorsa, non di nessuno degli interni.


2
Per quanto mi riguarda, questa è la risposta corretta. L'aggiornamento dei dati sul server non è un'operazione idempotente ed GETè un verbo del tutto inappropriato da usare. PUTè il verbo più appropriato poiché si può pensare che l'operazione aggiorni lo "stato ricaricato" della cache a "ricaricato".
Jez,

@Jez Delle risposte qui, preferisco anche questa. Attaccando con la metafora di posta elettronica, due piedi si fa sentire strano in un primo momento a pensare di inviare la posta mettendolo in stato di "invio" invece di invio di esso (un'azione). Ma se ci pensi, è davvero la stessa cosa che metterlo nella "posta in uscita". In effetti, il sistema di posta stesso probabilmente lo sta mettendo in coda in quel modo internamente quando gli dici di inviarlo. Quindi l'API può farti mettere la posta nello stato "invio" e l'API non è obbligata a spiegarsi oltre.
Craig,

Quindi per estensione, se non vuoi che il messaggio vada ancora, lo metti nello stato "programmato" con una data / ora in cui dovrebbe essere rilasciato. Se non è completo, lo metti (o è implicitamente / di default) nello stato "bozza", ecc.
Craig

... anche se penso che preferirei POST a PUT in questo caso, dal momento che PUT dovrebbe anche essere idempotente, ma POST non ha questo vincolo.
Craig,

1
Potresti farlo, ma alla fine sta cercando di inserire un piolo quadrato in un foro rotondo. Non vi è alcun motivo per cui il client debba attivare il server per "ricaricare" qualsiasi cosa, che è solo una cattiva progettazione architettonica. Il server può aggiornare il suo stato interno ad ogni chiamata o ad un intervallo di tempo fisso. Fare affidamento sul client per dire al server di ricaricare qualcosa di indipendente da qualsiasi richiesta effettiva per uno stato delle risorse non è un'architettura RESTful.
Cormac Mulhall,

32

Alcune delle altre risposte, inclusa quella accettata, ti consigliano di usare un GET (anche se non con molto entusiasmo).

Non sono d'accordo.

Prima di tutto, tutti gli altri che ti dicono che questo non è l'ideale e non è RESTful sono corretti. In uno scenario RESTful corretto, si stanno manipolando le risorse sul server e si aggiungono, si aggiornano, si eliminano, si recuperano, ecc. Tali risorse. Un PUT dovrebbe inviare un payload che rappresenti quale risorsa dovrebbe essere al termine della richiesta e POST dovrebbe inviare un payload che rappresenti una risorsa da aggiungere al server. E un GET dovrebbe restituire una risorsa sul server.

Hai un RPC (chiamata di procedura remota), che non è RESTful - vuoi fare qualcosa sul server. Quindi, se stai cercando di creare un'API puramente RESTful, dovresti riconsiderare ciò che stai facendo.

Detto questo, a volte è necessario piegare un po 'le regole. Soprattutto se stai sviluppando un'API interna che non sarà esposta al pubblico, potresti decidere che ne vale la pena.

In tal caso, consiglierei un PUT o POST, a seconda che l'RPC sia o meno idempotente .

In generale, diciamo che HTTP PUT è mappato su SQL UPDATE e HTTP POST è mappato su SQL INSERT, ma ciò non è assolutamente vero. Un modo più puro per affermare che HTTP PUT dovrebbe essere idempotente e HTTP POST non dovrebbe esserlo. Ciò significa che puoi chiamare la stessa richiesta PUT tutte le volte che vuoi senza effetti collaterali. Una volta che l'hai chiamato una volta è innocuo chiamarlo di nuovo. Ma non dovresti chiamare ripetutamente richieste POST a meno che tu non voglia: ogni POST modifica nuovamente i dati sul server.

Nel tuo caso, se hai bisogno di avere questa funzione di ricarica, ti consiglierei un PUT perché sembra idempotente. Ma ti esorto ancora a considerare ciò che gli altri hanno detto di non averne bisogno affatto.


6

POSTe PUTsono i verbi HTTP utilizzati per inviare un'entità a un server Web. Con PUT, l'entità inviata è la (nuova) rappresentazione per la risorsa nell'URI specificato, che non si adatta a ciò che si desidera. POSTè per il tradizionale gestore di moduli, in cui l'entità è dati accessori per la risorsa, quindi è il vincitore. L'entità includerebbe il comando o l'azione (ad esempio "azione = ricaricare").

Detto questo, il comando in questione probabilmente non dovrebbe essere esposto tramite un'interfaccia REST. Sembra che la necessità di "ricaricare" si presenti perché i dati possono essere modificati tramite qualche altro canale (ad es. Filesystem, client DB). Le cache dovrebbero essere trasparenti. Inoltre, le richieste HTTP dovrebbero essere atomiche, tenendo conto anche dei messaggi inviati su altri canali. Offrire un comando "ricaricare" per le impostazioni di configurazione sembra una complessità non necessaria; richiederlo è un design fragile. Esporre "ricaricare" per ripulire dopo un aggiornamento tramite un altro canale è sporco perché un canale non contiene l'intera conversazione. Invece, considera uno di:

  • effettuare aggiornamenti interamente tramite REST
  • esponendo i comandi all'altro canale
  • automatizzare le azioni

Alcune di queste opzioni potrebbero non essere praticabili, a seconda di quali altre restrizioni esistono.

Vedi anche " PUT vs POST in REST ".


Grazie. Ho rimosso il "interno" della modifica perché in realtà il metodo "ricaricare" è destinato a essere pubblico. Ho appena provato a dire che si riferisce al servizio web stesso. Penso che pubblicare "l'azione" sarebbe un buon approccio.
Renato Dinhani,

@ RenatoDinhaniConceição: anche senza "interno", odora ancora. Potrebbe essere sorprendente farti una nuova domanda se il design è buono.
uscita

4

Direi perché una richiesta del cliente dovrebbe esplicitamente effettuare una chiamata per aggiornare qualcosa del genere. Sembra che dovrebbe essere la logica nascosta su un'implementazione più tipica di GET (vale a dire i dati Pull, ma il servizio effettua un aggiornamento dei dati prima che vengano estratti) o da un altro trigger nel back-end lontano dal client.

Dopotutto, i dati / la configurazione dovrebbero essere aggiornati solo sulle chiamate successive, quindi mi spingerei più verso una chiamata pigra rispetto a quella desiderosa per un aggiornamento dei dati. Ovviamente sto assumendo molto qui, ma farei un passo indietro per rivalutare la necessità di una chiamata così esplicita e autonoma.


Guarda la mia modifica. "ricaricare" non è un comando che restituisce dati. Si riferisce al servizio web REST stesso. In termini generali, la mia domanda fa riferimento all'attivazione di azioni in un servizio Web REST. Altro esempio può essere: email_queue/stop_sending_emails. Sto solo dando un comando a qualcosa usando un'interfaccia RESTful.
Renato Dinhani,

5
Sono ancora d'accordo. Richiamare SIGHUP su un processo locale ha senso, poiché il computer dovrebbe fidarsi di qualcuno che ha effettuato l'accesso localmente e che abbia accesso a quel segnale. Ma per un protocollo senza stato, accessibile da Internet? Forse il servizio Web dovrebbe ricaricarsi automaticamente se necessario tramite polling o monitoraggio dei file. Questa chiamata dovrebbe essere completamente inutile.

1
Sono d'accordo. Cose come la configurazione e la memorizzazione nella cache devono essere trasparenti per il client. Forse dovresti darci una descrizione più concreta di una situazione in cui verrebbe chiamato il tuo endpoint.
Benjamin Hodgson,

3

Perché non trattare l'azione come una risorsa. Quindi, poiché si desidera aggiornare la cache, si POST una nuova azione nel sistema.

Per i puristi, potresti avere un URL dedicato per questo. Si noti che è possibile estenderlo e registrare le azioni effettive in un database (o qualsiasi altra memoria) con data, stato, utente, ecc ... Solo i miei pensieri qui.

Operazione / azioni / {azione} generiche a livello di sistema

Operazione specifica per un tipo di risorsa / azioni / {risorsa} / {azione}

Operazione specifica per una risorsa / azioni / {risorsa} / {id} / {azione}

Nel tuo caso, la cache è probabilmente a livello di sistema / actions / reload_cache


0

Quale verbo HTTP dovrei usare per attivare un'azione in un servizio web REST?

Quando si considerano i dettagli di un servizio REST, è spesso utile considerare questa euristica: come implementarlo con un sito Web?

HTML può descrivere in modo nativo solo richieste GET e POST. Quindi possiamo iniziare sono la ricerca lì.

È GETappropriato? Per rispondere a questa domanda, dobbiamo pensare alle ipotesi che i clienti e i componenti intermedi sono autorizzati a formulare GET. La semantica di GETè sicura

il client non richiede e non prevede alcuna modifica dello stato sul server di origine a seguito dell'applicazione di un metodo sicuro a una risorsa di destinazione. Allo stesso modo, non è previsto che l'uso ragionevole di un metodo sicuro possa causare danni, perdita di proprietà o oneri insoliti sul server di origine.

L'implicazione, quindi, è che i clienti e i componenti intermedi hanno la facoltà di invocare una richiesta GET con la frequenza necessaria per soddisfare le proprie preoccupazioni. I ragni possono ottenere risorse indiscriminatamente per aggiornare i loro indici. Le cache possono essere pre-recuperate. Su una rete inaffidabile, i messaggi persi possono essere ritentati con la frequenza necessaria per garantire almeno una risposta.

Sarà utilizzato per ricaricare configurazioni, cache, ecc.

Se queste sono cose costose da fare, forse non vuoi che i clienti emettano queste richieste a loro discrezione.

POSTd'altra parte, è effettivamente non vincolato: ciò riduce notevolmente le ipotesi che i clienti generici sono autorizzati a fare. Non si ottengono componenti che fanno richieste POST speculative perché sarebbero difettose nel farlo - nulla nello standard dice che va bene.

PUT, PATCH, DELETE... questi sono metodi sicuri con una semantica più specifici rispetto POST; se sono appropriati dipenderà o meno dal tuo modello di risorsa.

Un'idea importante da tenere a mente è che i metodi HTTP appartengono al dominio del documento (vedi il discorso di Jim Webber del 2011 ), gli effetti che stai descrivendo probabilmente non fanno parte del dominio del documento, ma sono invece gli effetti collaterali invocati quando i documenti vengono cambiati . Ciò ti dà molta libertà in termini di organizzazione dei documenti per svolgere il lavoro.

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.