PUT vs. POST in REST


5373

Secondo le specifiche HTTP / 1.1:

Il POSTmetodo viene utilizzato per richiedere che il server di origine accetta l'entità racchiusa nella richiesta come nuova subordinata della risorsa identificata dal Request-URInelRequest-Line

In altre parole, POSTviene utilizzato per creare .

Il PUTmetodo richiede che l'entità racchiusa sia archiviata sotto quella fornita Request-URI. Se si Request-URIriferisce a una risorsa già esistente, l'entità inclusa DOVREBBE essere considerata come una versione modificata di quella residente sul server di origine. Se Request-URInon punta a una risorsa esistente e quell'URI è in grado di essere definito come una nuova risorsa dall'agente utente richiedente, il server di origine può creare la risorsa con quell'URI. "

Cioè, PUTviene utilizzato per creare o sostituire .

Quindi, quale dovrebbe essere usato per creare una risorsa? O è necessario supportare entrambi?


56
Può essere utile usare le definizioni in HTTPbis - Roy ha messo un bel po 'di lavoro per chiarirle. Vedi: tools.ietf.org/html/…
Mark Nottingham,

16
Solo per portare il commento di @ MarkNottingham all'ultima revisione, ecco POST e PUT , come definito su HTTPbis.
Marius Butuc,

37
Mi sembra che questo dibattito sia nato dalla pratica comune di semplificare eccessivamente il REST descrivendo i metodi HTTP in termini di operazioni CRUD.
Stuporman,

5
Sfortunatamente le prime risposte sono sbagliate sul POST. Controllare la mia risposta per una migliore spiegazione delle differenze: stackoverflow.com/a/18243587/2458234
7hi4g0

23
PUT e POST sono entrambi metodi non sicuri. Tuttavia, PUT è idempotente, mentre POST non lo è. - Vedi di più su: restcookbook.com/HTTP%20Methods/put-vs-post/…
Dinesh Saini

Risposte:


4239

Complessivamente:

Sia PUT che POST possono essere utilizzati per la creazione.

Devi chiedere "a che cosa stai eseguendo l'azione?" per distinguere cosa dovresti usare. Supponiamo che tu stia progettando un'API per porre domande. Se si desidera utilizzare POST, è necessario farlo in un elenco di domande. Se vuoi usare PUT, lo faresti per una domanda particolare.

Entrambi possono essere usati alla grande, quindi quale dovrei usare nel mio design RESTful:

Non è necessario supportare sia PUT che POST.

Chi viene usato è lasciato a te. Ma ricorda di usare quello giusto in base all'oggetto a cui fai riferimento nella richiesta.

Alcune considerazioni:

  • Dai un nome agli oggetti URL che crei esplicitamente o lasci che il server decida? Se li chiami, usa PUT. Se si lascia decidere al server, utilizzare POST.
  • PUT è idempotente, quindi se metti un oggetto due volte, non ha alcun effetto. Questa è una bella proprietà, quindi vorrei usare PUT quando possibile.
  • È possibile aggiornare o creare una risorsa con PUT con lo stesso URL oggetto
  • Con POST è possibile ricevere 2 richieste contemporaneamente apportando modifiche a un URL e possono aggiornare diverse parti dell'oggetto.

Un esempio:

Ho scritto quanto segue come parte di un'altra risposta su SO riguardo a questo :

INVIARE:

Utilizzato per modificare e aggiornare una risorsa

POST /questions/<existing_question> HTTP/1.1
Host: www.example.com/

Si noti che quanto segue è un errore:

POST /questions/<new_question> HTTP/1.1
Host: www.example.com/

Se l'URL non è ancora stato creato, non dovresti utilizzare POST per crearlo mentre specifichi il nome. Ciò dovrebbe comportare un errore "risorsa non trovata" perché <new_question>non esiste ancora. Dovresti prima mettere la <new_question> risorsa sul server.

Potresti però fare qualcosa del genere per creare risorse usando POST:

POST /questions HTTP/1.1
Host: www.example.com/

Si noti che in questo caso il nome della risorsa non è specificato, il percorso URL dei nuovi oggetti verrebbe restituito.

METTERE:

Utilizzato per creare una risorsa o sovrascriverla. Mentre specifichi le risorse nuovo URL.

Per una nuova risorsa:

PUT /questions/<new_question> HTTP/1.1
Host: www.example.com/

Per sovrascrivere una risorsa esistente:

PUT /questions/<existing_question> HTTP/1.1
Host: www.example.com/

Inoltre, e un po 'più concisamente, RFC 7231 Sezione 4.3.4 PUT afferma (enfasi aggiunta),

4.3.4. METTERE

Il metodo PUT richiede che lo stato della risorsa di destinazione sia createdo replacedcon lo stato definito dalla rappresentazione racchiusa nel payload del messaggio di richiesta.


1026
Penso che non si possa sottolineare abbastanza il fatto che PUT è idempotente: se la rete viene maltrattata e il client non è sicuro che la sua richiesta sia passata, può semplicemente inviarla una seconda (o centesima) volta, ed è garantita dal Specifica HTTP che questo ha esattamente lo stesso effetto dell'invio una volta.
Jörg W Mittag,

77
@ Jörg W Mittag: non necessario. La seconda volta potrebbe restituire 409 Conflict o qualcosa del genere se la richiesta è stata modificata nel frattempo (da un altro utente o la prima richiesta stessa, che ha ricevuto).
Mitar,

632
Se non sbaglio, ciò che dovremmo sottolineare è che PUT è definito idempotente. Devi ancora scrivere il tuo server in modo tale che PUT si comporti correttamente, sì? Forse è meglio dire "PUT fa sì che il trasporto assuma idempotenza, il che può influire sul comportamento del trasporto, ad esempio la memorizzazione nella cache".
Ian Ni-Lewis,

150
@ JörgWMittag Idempotence catchphrase? Che ne dici di "Invia e invia e invia il mio amico, alla fine non fa differenza".
James Beninger

39
Pensa a loro come: PUT = inserisci o aggiorna; POST = inserisci. Quindi quando fai due PUT - ottieni un nuovo record, quando fai due POST - ottieni due nuovi record.
Eugen Konkov,

2218

Puoi trovare affermazioni sul Web che dicono

Nessuno dei due ha ragione.


Meglio scegliere tra PUT e POST in base all'idempotenza dell'azione.

PUT implica mettere una risorsa, sostituendo completamente tutto ciò che è disponibile nell'URL specificato con una cosa diversa. Per definizione, un PUT è idempotente. Fallo tutte le volte che vuoi e il risultato è lo stesso. x=5è idempotente. Puoi mettere una risorsa se esiste in precedenza o meno (ad esempio, per creare o aggiornare)!

POST aggiorna una risorsa, aggiunge una risorsa sussidiaria o provoca una modifica. Un POST non è idempotente, nel modo in cui x++non è idempotente.


Con questo argomento, PUT serve a creare quando conosci l'URL della cosa che creerai. POST può essere utilizzato per creare quando si conosce l'URL della "fabbrica" ​​o del gestore per la categoria di cose che si desidera creare.

così:

POST /expense-report

o:

PUT  /expense-report/10929

72
Sono d'accordo, per quanto riguarda l'idempotenza, dovrebbe superare qualsiasi altra preoccupazione poiché sbagliare può causare molti molti bug imprevisti.
Josh,

16
Se POST è in grado di aggiornare una risorsa, in che modo non è idempotente? Se cambio l'età degli studenti usando PUT e lo faccio 10 volte, l'età degli studenti è la stessa se l'ho fatto una volta.
Jack Ukleja,

28
@Schneider, in questo caso il tuo server sta facendo uno sforzo extra per garantire l'idempotenza, ma non lo sta pubblicizzando. I browser avvertiranno comunque l'utente se tentano di ricaricare tale richiesta POST.
Tobu,

47
@Schneider POST può creare una risorsa sussidiaria; quindi puoi POST da raccogliere, come POST / note spese e creerebbe sul tuo server quante entità (note spese) quante sono le richieste che hai inviato, anche se sono completamente simili. Pensa a come inserire la stessa riga nella tabella DB (/ note spese) con chiave primaria auto-incrementata. I dati rimangono gli stessi, la chiave (URI in questo caso) viene generata dal server ed è diversa per ogni altro inserto (richiesta). Pertanto, l'effetto POST può essere idempotente, ma potrebbe anche non esserlo . Quindi, POST non è idempotente.
Snifff,

11
Diciamo che abbiamo entità che possono avere due proprietà - namee date. Se abbiamo un'entità con un esistente namee date, ma poi facciamo richieste specificando solo un name, il comportamento corretto di PUT sarebbe quello di cancellare datequello dell'entità, mentre POST può aggiornare solo le proprietà specificate, lasciando le proprietà non specificate come erano prima che la richiesta fosse fatta. Sembra corretto / ragionevole o è un uso improprio di PUT (ho visto riferimenti a PATCH , che sembra essere più appropriato, ma non esiste ancora)?
Jon z

707
  • POST a un URL crea una risorsa figlio in un URL definito dal server .
  • MESSA a un URL crea / sostituisce la risorsa nella sua interezza nell'URL definito dal client .
  • PATCH su un URL aggiorna parte della risorsa nell'URL definito dal client.

La specifica pertinente per PUT e POST è RFC 2616 §9.5ff.

POST crea una risorsa figlio , quindi POST /itemscrea una risorsa che vive sotto la /itemsrisorsa. Per esempio. /items/1. L'invio due volte dello stesso pacchetto postale creerà due risorse.

PUT serve per creare o sostituire una risorsa in un URL conosciuto dal client .

Pertanto: PUT è solo un candidato per CREATE in cui il client conosce già l'URL prima della creazione della risorsa. Per esempio. /blogs/nigel/entry/when_to_use_post_vs_putpoiché il titolo viene utilizzato come chiave di risorsa

PUT sostituisce la risorsa all'URL noto se esiste già, quindi l'invio della stessa richiesta due volte non ha alcun effetto. In altre parole, le chiamate a PUT sono idempotenti .

L'RFC legge così:

La differenza fondamentale tra le richieste POST e PUT si riflette nel diverso significato di Request-URI. L'URI in una richiesta POST identifica la risorsa che gestirà l'entità chiusa. Tale risorsa potrebbe essere un processo di accettazione dei dati, un gateway verso qualche altro protocollo o un'entità separata che accetta le annotazioni. Al contrario, l'URI in una richiesta PUT identifica l'entità racchiusa nella richiesta: l'agente utente sa cosa è destinato l'URI e il server NON DEVE tentare di applicare la richiesta ad altre risorse. Se il server desidera che la richiesta venga applicata a un URI diverso,

Nota: PUT è stato principalmente utilizzato per aggiornare le risorse (sostituendole nella loro interezza), ma recentemente si è spostato verso l'utilizzo di PATCH per l'aggiornamento delle risorse esistenti, poiché PUT specifica che sostituisce l'intera risorsa. RFC 5789.

Aggiornamento 2018 : esiste un caso che può essere fatto per evitare PUT. Vedi "RESTO senza PUT"

Con la tecnica "REST senza PUT", l'idea è che i consumatori siano costretti a pubblicare nuove risorse di richiesta "nominate". Come discusso in precedenza, la modifica dell'indirizzo postale di un cliente è un POST in una nuova risorsa "ChangeOfAddress", non un PUT di una risorsa "Cliente" con un valore di campo dell'indirizzo postale diverso.

tratto da REST API Design - Resource Modeling di Prakash Subramaniam di Thoughtworks

Ciò impone all'API di evitare problemi di transizione dello stato con più client che aggiornano una singola risorsa e si abbina più facilmente con il sourcing degli eventi e il CQRS. Quando il lavoro viene eseguito in modo asincrono, POSTARE la trasformazione e attendere che venga applicata sembra appropriato.


53
O dall'altra parte della barriera: PUT se il client determina l'indirizzo della risorsa risultante, POST se il server lo fa.
DanMan,

3
Penso che questa risposta debba essere modificata per rendere più chiaro ciò che @DanMan ha indicato in modo molto semplice. Quello che trovo più prezioso qui è la nota alla fine, che afferma che un PUT dovrebbe essere usato solo per sostituire l'intera risorsa.
Hermes,

3
PATCH non è un'opzione realistica per almeno alcuni anni, ma sono d'accordo con l'ideologia.
schiaccia il

4
Sto cercando di capire, ma usare PUT per creare qualcosa avrebbe senso solo se il client fosse sicuro che la risorsa non esiste ancora, giusto? Seguendo l'esempio del blog, supponi di aver creato centinaia di post sul blog in un paio d'anni, quindi scegli accidentalmente lo stesso titolo che hai fatto per un post due anni fa. Ora sei andato a sostituire quel post, che non era previsto. Quindi usare PUT per creare richiederebbe al cliente di tracciare ciò che viene preso e ciò che non lo è, e potrebbe portare a incidenti e effetti collaterali non previsti, oltre ad avere percorsi che fanno due cose completamente diverse?
galaxyAbstractor

5
Hai ragione. Mettere un post sul blog nello stesso url di uno esistente provocherebbe un aggiornamento a quel post esistente (anche se ovviamente si potrebbe verificare prima con un GET). Questo indica perché sarebbe una cattiva idea usare solo il titolo come URL. Funzionerebbe comunque ovunque ci fosse una chiave naturale nei dati ... che nella mia esperienza è rara. O se hai usato i GUID
Nigel Thorne il

221

Sommario:

Creare:

Può essere eseguito con PUT o POST nel modo seguente:

METTERE

Crea IL nuova risorsa con newResourceId come identificatore, sotto le risorse / URI, o di raccolta .

PUT /resources/<newResourceId> HTTP/1.1 

INVIARE

Crea una nuova risorsa sotto l'URI / risorse o raccolta . Di solito l'identificatore viene restituito dal server.

POST /resources HTTP/1.1

Aggiornare:

Può essere eseguito solo con PUT nel modo seguente:

METTERE

Aggiorna la risorsa con esistenteResourceId come identificatore, sotto l'URI / resources o raccolta .

PUT /resources/<existingResourceId> HTTP/1.1

Spiegazione:

Quando hai a che fare con REST e URI in generale, hai generici a sinistra e specifici a destra . I generici sono generalmente chiamati raccolte e gli elementi più specifici possono essere chiamati risorse . Si noti che una risorsa può contenere una raccolta .

Esempi:

<- generico - specifico ->

URI: website.com/users/john
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource

URI:website.com/users/john/posts/23
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource
posts        - collection of posts from john
23           - post from john with identifier 23, also a resource

Quando usi POST ti riferisci sempre a una raccolta , quindi ogni volta che dici:

POST /users HTTP/1.1

stai pubblicando un nuovo utente nella raccolta utenti .

Se vai avanti e prova qualcosa del genere:

POST /users/john HTTP/1.1

funzionerà, ma semanticamente stai dicendo che vuoi aggiungere una risorsa alla raccolta john sotto la raccolta utenti .

Una volta che si utilizza PUT, ci si riferisce a una risorsa o a un singolo elemento, possibilmente all'interno di una raccolta . Quindi quando dici:

PUT /users/john HTTP/1.1

stai dicendo all'aggiornamento del server o crea, se non esiste, la risorsa john nella raccolta utenti .

Spec:

Vorrei evidenziare alcune parti importanti delle specifiche:

INVIARE

Il metodo POST viene utilizzato per richiedere che il server di origine accetti l'entità racchiusa nella richiesta come nuovo subordinato della risorsa identificata dall'URI di richiesta nella riga di richiesta

Quindi, crea una nuova risorsa in una raccolta .

METTERE

Il metodo PUT richiede che l'entità inclusa sia archiviata nell'URI di richiesta fornito. Se l'URI della richiesta fa riferimento a una risorsa già esistente , l'entità inclusa DOVREBBE essere considerata come una versione modificata di quella residente sul server di origine. Se l'URI di richiesta non punta a una risorsa esistente e tale URI può essere definito come una nuova risorsa dall'agente utente richiedente, il server di origine può creare la risorsa con tale URI. "

Quindi, creare o aggiornare in base all'esistenza della risorsa .

Riferimento:


11
Questo post mi è stato utile nel capire che POST aggiunge "qualcosa" come bambino alla raccolta (URI) data, mentre PUT definisce esplicitamente il "qualcosa" nella posizione URI data.
kwah,

3
Questa è la risposta migliore, qui, penso: nessuna di queste assurdità "POST può aggiornare una risorsa". Mi piace la tua affermazione, "L'aggiornamento può essere eseguito solo con PUT".
Thomas,

4
No, PUT non è per l'aggiornamento o la creazione. È per la sostituzione. Nota che non puoi sostituire nulla con qualcosa per l'effetto della creazione.
thecoshman,

2
@ 7hi4g0 PUT è per l'aggiornamento con una sostituzione completa, in altre parole, sostituisce. Non sostituisci nulla con qualcosa o qualcosa con qualcosa di completamente nuovo. PUT non serve per apportare una modifica minore (a meno che il client non apporti tale modifica minore e fornisca l'intera nuova versione, anche ciò che rimane invariato). Per una modifica parziale, PATCH è il metodo di scelta.
thecoshman,

1
@thecoshman Potresti, ma non sarebbe troppo chiaro che anche la creazione sia coperta. In questo caso, è meglio essere espliciti.
7hi4g0,

175

POST significa "crea nuovo" come in "Ecco l'input per la creazione di un utente, crealo per me".

PUT significa "inserisci, sostituisci se esiste già" come in "Ecco i dati per l'utente 5".

È possibile POSTad esempio.com/utente poiché non si conosce URLancora l'utente, si desidera che il server lo crei.

È PUTpossibile example.com/users/id poiché si desidera sostituire / creare un utente specifico .

POSTARE due volte con gli stessi dati significa creare due utenti identici con ID diversi. Mettere due volte con gli stessi dati crea il primo utente e lo aggiorna allo stesso stato la seconda volta (nessuna modifica). Dal momento che alla fine PUTsi ottiene lo stesso stato, non importa quante volte lo si esegue, si dice che sia "ugualmente potente" ogni volta - idempotente. Questo è utile per riprovare automaticamente le richieste. Non più "sei sicuro di voler inviare nuovamente" quando premi il pulsante Indietro sul browser.

Un consiglio generale è da utilizzare POSTquando è necessario che il server abbia il controllo della URLgenerazione delle risorse. Utilizzare PUTaltrimenti. Preferisco PUT finita POST.


12
La sciattezza può aver causato l'insegnamento comune che sono necessari solo due verbi: GET e POST. OTTIENI per ottenere, POST per cambiare. Anche PUT e DELETE sono stati eseguiti utilizzando POST. Chiedere cosa significhi davvero PUT 25 anni dopo, forse un segno che all'inizio abbiamo imparato male. La popolarità di REST ha riportato le persone alle basi in cui ora dobbiamo disimparare errori passati. POST era abusato e ora comunemente insegnato in modo errato. Parte migliore: "POSTARE due volte con gli stessi dati significa creare due [risorse] identiche". Ottimo punto!
maxpolk

1
Come puoi usare PUT per creare un record con l'ID, come nel tuo esempio user 5se non esiste ancora? Non intendi update, replace if already exists? o qualcosa del genere
Luca,

@Coulton: intendevo quello che ho scritto. Inserite l'utente 5 se MESSI a / users / 5 e # 5 non esiste ancora.
Alexander Torstling,

@Coulton: E PUTpuò anche essere usato per sostituire il valore di una risorsa esistente nella sua interezza.
DavidRR

1
"Preferisci il PUT al POST" ... vuoi giustificarlo?
thecoshman,

173

Vorrei aggiungere il mio consiglio "pragmatico". Utilizzare PUT quando si conosce "id" con cui è possibile recuperare l'oggetto che si sta salvando. L'uso di PUT non funzionerà troppo bene se, ad esempio, è necessario un ID generato dal database da restituire per eseguire ricerche o aggiornamenti futuri.

Quindi: per salvare un utente esistente o uno in cui il client genera l'id ed è stato verificato che l'id è univoco:

PUT /user/12345 HTTP/1.1  <-- create the user providing the id 12345
Host: mydomain.com

GET /user/12345 HTTP/1.1  <-- return that user
Host: mydomain.com

In caso contrario, utilizzare POST per creare inizialmente l'oggetto e PUT per aggiornare l'oggetto:

POST /user HTTP/1.1   <--- create the user, server returns 12345
Host: mydomain.com

PUT /user/12345 HTTP/1.1  <--- update the user
Host: mydomain.com

17
In realtà, dovrebbe essere POST /users. (Si noti che /usersè plurale.) Ciò ha l'effetto di creare un nuovo utente e renderlo una risorsa figlio della /usersraccolta.
DavidRR

6
A dire il vero @DavidRR, come gestire i gruppi è un altro dibattito. GET /usersha senso, si legge come vuoi, ma sarei d'accordo con GET /user/<id>o POST /user(con payload per detto nuovo utente) perché legge correttamente "get me users 5" è strano, ma "get me user 5" è più naturale. Probabilmente sarei comunque caduto dal lato della pluralizzazione :)
Thoshoshman l'

126

Usa POST per creare e PUT per aggiornare. È così che lo fa Ruby on Rails.

PUT    /items/1      #=> update
POST   /items        #=> create

4
POST /itemsaggiunge un nuovo elemento a una risorsa già definita ('item'). Come dice la risposta, non "crea un gruppo". Non capisco perché questo abbia 12 voti.
David J.

Immediatamente, Rails non supporta la "creazione di un gruppo" tramite REST. Per "creare un gruppo", intendo "creare una risorsa", è necessario farlo tramite il codice sorgente.
David J.

8
Questa è una linea guida giusta, ma una semplificazione eccessiva. Come menzionano le altre risposte, entrambi i metodi potrebbero essere utilizzati sia per creare che per aggiornare.
Brad Koch,

2
Concordo con la risposta con una leggera modifica. Utilizzare POST per creare e PUT per aggiornare completamente la risorsa. Per aggiornamenti parziali, possiamo usare PUT o PATCH. Diciamo che vogliamo aggiornare lo stato di un gruppo. Possiamo usare PUT / groups / 1 / status con lo stato è il payload della richiesta o PATCH / groups / 1 con i dettagli sull'azione nel payload
java_geek

2
Dovrebbe anche essere chiarito che PUT /items/42è valido anche per la creazione di una risorsa, ma solo se il client ha il privilegio di nominare la risorsa . (Rails consente a un client questo privilegio di denominazione?)
DavidRR

123

Entrambi sono usati per la trasmissione dei dati tra client e server, ma ci sono sottili differenze tra loro, che sono:

Inserisci qui la descrizione dell'immagine

Analogia:

  • Metti cioè prendi e metti dove era.
  • POST come posta inviare posta ufficio.

inserisci qui la descrizione dell'immagine

Analogia sui social media / rete:

  • Post sui social media: quando pubblichiamo un messaggio, crea un nuovo post.
  • Inserisci (cioè modifica) per il messaggio che abbiamo già pubblicato.

21
@MobileMon No, i metodi REST non sono CRUD.
jlr

1
Direi PUT per UPSERTS
Hola Soy Edu Feliz Navidad,

@MobileMon no: POST quando si crea una nuova risorsa e non si conosce l'endpoint finale per ottenerlo. PUT per altri casi.
Portekoi,

67

REST è un molto il concetto di alto livello. In realtà, non menziona nemmeno HTTP!

Se hai dei dubbi su come implementare REST in HTTP, puoi sempre dare un'occhiata alla specifica Atom Publication Protocol (AtomPub) . AtomPub è uno standard per la scrittura di servizi Web RESTful con HTTP sviluppato da molti luminari HTTP e REST, con alcuni input di Roy Fielding, l'inventore di REST e (co) inventore dello stesso HTTP.

In effetti, potresti persino essere in grado di utilizzare direttamente AtomPub. Mentre è uscito dalla comunità dei blog, non è in alcun modo limitato ai blog: è un protocollo generico per interagire RESTAMENTE con raccolte arbitrarie (nidificate) di risorse arbitrarie tramite HTTP. Se puoi rappresentare la tua applicazione come una raccolta nidificata di risorse, puoi semplicemente usare AtomPub e non preoccuparti se usare PUT o POST, quali codici di stato HTTP restituire e tutti quei dettagli.

Questo è ciò che AtomPub ha da dire sulla creazione di risorse (sezione 9.2):

Per aggiungere membri a una raccolta, i client inviano richieste POST all'URI della raccolta.


8
Non c'è niente di sbagliato nel consentire a PUT di creare risorse. Basta essere consapevoli del fatto che significa che il client fornisce l'URL.
Julian Reschke,

5
C'è qualcosa di molto sbagliato nel consentire a PUT di creare risorse: il client fornisce l'URL. Questo è il lavoro del server!
Joshcodes,

@Joshcodes Non sempre è compito del server creare ID client. Ho visto sempre più progetti che consentono ai clienti di generare una sorta di UUID come ID risorsa. Questo design si presta in particolare per aumentare la scala.
Justin Ohms,

@JustinOhms Concordo con il tuo punto sugli ID generati dal cliente (nota a margine: tutti i sistemi progettati da me dal 2008 circa richiedono al cliente di creare l'ID come UUID / Guid). Ciò non significa che il client debba specificare l'URL.
Joshcodes

1
Sì, se la risorsa esiste già, utilizzare PUT. Tuttavia, in quasi tutti i casi, le risorse devono essere create con POST e il client non deve fornire l'URL. Roy Fielding è d'accordo con questa affermazione FWIW: roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
Joshcodes

61

La decisione se utilizzare PUT o POST per creare una risorsa su un server con un'API HTTP + REST si basa su chi possiede la struttura dell'URL. Avere il cliente a conoscenza o partecipare alla definizione, la struttura dell'URL è un accoppiamento non necessario affine agli accoppiamenti indesiderati che sono sorti dalla SOA. La fuga di tipi di giunti è la ragione per cui REST è così popolare. Pertanto, il metodo corretto da utilizzare è POST. Esistono eccezioni a questa regola e si verificano quando il client desidera mantenere il controllo sulla struttura della posizione delle risorse distribuite. Questo è raro e probabilmente significa che qualcos'altro è sbagliato.

A questo punto alcune persone sostengono che se si utilizzano RESTful-URL , il client conosce l'URL della risorsa e quindi un PUT è accettabile. Dopotutto, questo è il motivo per cui gli URL canonici, normalizzati, Ruby on Rails, Django sono importanti, guarda l'API di Twitter ... blah blah blah. Quelle persone devono capire che non esiste un URL Restful e che lo stesso Roy Fielding afferma che :

Un'API REST non deve definire nomi o gerarchie di risorse fisse (un ovvio accoppiamento di client e server). I server devono avere la libertà di controllare il proprio spazio dei nomi. Consentire invece ai server di istruire i clienti su come costruire URI appropriati, ad esempio nei moduli HTML e nei modelli URI, definendo tali istruzioni all'interno dei tipi di media e delle relazioni di collegamento. [Il fallimento qui implica che i clienti stanno assumendo una struttura di risorse a causa di informazioni fuori banda, come uno standard specifico del dominio, che è l'equivalente orientato ai dati all'accoppiamento funzionale di RPC].

http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

L'idea di un RESTful-URL è in realtà una violazione di REST in quanto il server è responsabile della struttura dell'URL e dovrebbe essere libero di decidere come usarlo per evitare l'accoppiamento. Se questo ti confonde, leggi il significato dell'auto-scoperta sul design dell'API.

L'uso di POST per creare risorse comporta una considerazione progettuale perché POST non è idempotente. Ciò significa che ripetere più volte un POST non garantisce lo stesso comportamento ogni volta. Questo spaventa le persone a usare PUT per creare risorse quando non dovrebbero. Sanno che è sbagliato (POST è per CREATE) ma lo fanno comunque perché non sanno come risolvere questo problema. Questa preoccupazione è dimostrata nella seguente situazione:

  1. Il client POST una nuova risorsa sul server.
  2. Il server elabora la richiesta e invia una risposta.
  3. Il client non riceve mai la risposta.
  4. Il server non è a conoscenza del client non ha ricevuto la risposta.
  5. Il client non ha un URL per la risorsa (quindi PUT non è un'opzione) e ripete il POST.
  6. Il POST non è idempotente e il server ...

Il passaggio 6 è dove le persone sono confuse su cosa fare. Tuttavia, non esiste alcun motivo per creare un kludge per risolvere questo problema. Invece, HTTP può essere utilizzato come specificato in RFC 2616 e il server risponde:

10.4.10 409 Conflitto

Impossibile completare la richiesta a causa di un conflitto con lo stato corrente della risorsa. Questo codice è consentito solo nelle situazioni in cui è previsto che l'utente possa essere in grado di risolvere il conflitto e inviare nuovamente la richiesta. Il corpo di risposta DOVREBBE includere abbastanza

informazioni affinché l'utente possa riconoscere l'origine del conflitto. Idealmente, l'entità di risposta dovrebbe includere informazioni sufficienti per l'utente o l'agente utente per risolvere il problema; tuttavia, ciò potrebbe non essere possibile e non è necessario.

È più probabile che si verifichino conflitti in risposta a una richiesta PUT. Ad esempio, se si utilizzava il controllo delle versioni e l'entità in fase di PUT includeva modifiche a una risorsa in conflitto con quelle fatte da una richiesta precedente (di terze parti), il server potrebbe utilizzare la risposta 409 per indicare che non è possibile completare la richiesta . In questo caso, l'entità della risposta conterrebbe probabilmente un elenco delle differenze tra le due versioni in un formato definito dal Content-Type di risposta.

Rispondere con un codice di stato di 409 Conflict è il ricorso corretto perché :

  • L'esecuzione di un POST di dati che ha un ID che corrisponde a una risorsa già nel sistema è "un conflitto con lo stato corrente della risorsa".
  • Poiché la parte importante è che il client capisca che il server ha la risorsa e che intraprende le azioni appropriate. Questa è una "situazione / e in cui si prevede che l'utente possa essere in grado di risolvere il conflitto e inviare nuovamente la richiesta".
  • Una risposta che contiene l'URL della risorsa con l'ID in conflitto e le condizioni preliminari appropriate per la risorsa fornirebbe "informazioni sufficienti per l'utente o l'agente utente per risolvere il problema", che è il caso ideale per RFC 2616.

Aggiornamento basato sul rilascio di RFC 7231 per sostituire 2616

RFC 7231 è progettato per sostituire 2616 e nella Sezione 4.3.3 descrive la seguente possibile risposta per un POST

Se il risultato dell'elaborazione di un POST equivale a una rappresentazione di una risorsa esistente, un server di origine può reindirizzare l'agente utente a tale risorsa inviando una risposta 303 (Vedi altro) con l'identificatore della risorsa esistente nel campo Posizione. Ciò ha i vantaggi di fornire all'agente utente un identificatore di risorse e di trasferire la rappresentazione tramite un metodo più suscettibile alla memorizzazione nella cache condivisa, sebbene a costo di una richiesta aggiuntiva se l'agente utente non ha già la rappresentazione memorizzata nella cache.

Ora potrebbe essere allettante restituire semplicemente un 303 nel caso in cui venga ripetuto un POST. Comunque, l'opposto è vero. Restituire un 303 avrebbe senso solo se più richieste di creazione (creazione di risorse diverse) restituiscono lo stesso contenuto. Un esempio potrebbe essere un "grazie per aver inviato il messaggio di richiesta" che il client non deve scaricare nuovamente ogni volta. RFC 7231 sostiene ancora nella sezione 4.2.2 che il POST non deve essere idempotente e continua a sostenere che il POST dovrebbe essere usato per creare.

Per ulteriori informazioni a riguardo, leggi questo articolo .


Una risposta al conflitto 409 sarebbe il codice appropriato per qualcosa come tentare di creare un nuovo account con un nome utente già esistente? Ho usato 409 per i conflitti di versione in modo specifico, ma dopo aver letto la tua risposta, mi chiedo se non dovrebbe essere usato per richieste "duplicate".
Eric B.

@EricB. Sì, nella situazione descritta "a causa di un conflitto con lo stato corrente della risorsa" l'operazione non riesce. Inoltre, è ragionevole aspettarsi che l'utente possa risolvere il conflitto e il corpo del messaggio deve solo informare l'utente che il nome utente esiste già.
Joshcodes,

@Joshcodes puoi dire di più sul processo di risoluzione dei conflitti? In questo caso, se il nome utente esiste già, il client dovrebbe richiedere all'utente finale un nome utente diverso? Cosa succede se il client sta effettivamente cercando di utilizzare POST per modificare il nome utente? Le richieste PUT devono comunque essere utilizzate per l'aggiornamento dei parametri, mentre POST viene utilizzato per la creazione di oggetti, uno alla volta o più? Grazie.
BFar

@ BFar2 se il nome utente esiste già, il client dovrebbe richiedere all'utente. Per modificare il nome utente, supponendo che il nome utente faccia parte di una risorsa già creata che deve essere modificata, PUT verrebbe utilizzato perché si è corretti, POST viene utilizzato per creare, sempre e PUT per gli aggiornamenti.
Joshcodes

spiegare le cose usando un linguaggio breve ed efficace è anche un'abilità desiderabile
Junchen Liu,

53

Mi piace questo consiglio, dalla definizione di PUT di RFC 2616 :

La differenza fondamentale tra le richieste POST e PUT si riflette nel diverso significato di Request-URI. L'URI in una richiesta POST identifica la risorsa che gestirà l'entità chiusa. Tale risorsa potrebbe essere un processo di accettazione dei dati, un gateway verso qualche altro protocollo o un'entità separata che accetta le annotazioni. Al contrario, l'URI in una richiesta PUT identifica l'entità racchiusa nella richiesta: l'agente utente sa cosa è destinato l'URI e il server NON DEVE tentare di applicare la richiesta ad altre risorse.

Questo è in contrasto con gli altri consigli qui, che PUT è meglio applicato alle risorse che hanno già un nome e POST è buono per creare un nuovo oggetto sotto una risorsa esistente (e lasciare che il server lo assegni).

Interpreto questo e i requisiti di idempotenza su PUT, nel senso che:

  • POST è utile per creare nuovi oggetti in una raccolta (e creare non deve essere idempotente)
  • PUT è buono per l'aggiornamento di oggetti esistenti (e l'aggiornamento deve essere idempotente)
  • Il POST può anche essere utilizzato per aggiornamenti non idempotenti di oggetti esistenti (in particolare, cambiare parte di un oggetto senza specificare tutto - se ci pensi, la creazione di un nuovo membro di una raccolta è in realtà un caso speciale di questo tipo di aggiornamento, dal punto di vista della collezione)
  • PUT può essere utilizzato anche per creare se e solo se si consente al client di assegnare un nome alla risorsa. Ma dal momento che i client REST non dovrebbero fare ipotesi sulla struttura degli URL, questo è meno nello spirito previsto delle cose.

3
"POST può essere utilizzato anche per aggiornamenti non idempotenti di oggetti esistenti (in particolare, cambiando parte di un oggetto senza specificare tutto" Ecco a cosa serve PATCH
Snuggs

48

In breve:

PUT è idempotente, in cui lo stato della risorsa sarà lo stesso se la stessa operazione viene eseguita una volta o più volte.

POST è non idempotente, in cui lo stato della risorsa può variare se l'operazione viene eseguita più volte rispetto all'esecuzione una sola volta.

Analogia con query di database

PUT Puoi pensare a "UPDATE STUDENT SET address =" abc "dove id =" 123 ";

POST Puoi pensare a qualcosa come "INSERT INTO STUDENT (nome, indirizzo) VALUES (" abc "," xyzzz ");

L'ID studente viene generato automaticamente.

Con PUT, se la stessa query viene eseguita più volte o una volta, lo stato della tabella STUDENT rimane lo stesso.

In caso di POST, se la stessa query viene eseguita più volte, vengono creati più record Student nel database e lo stato del database cambia ad ogni esecuzione di una query "INSERT".

NOTA: PUT ha bisogno di un percorso di risorse (già risorsa) su cui deve avvenire l'aggiornamento, mentre POST non lo richiede. Pertanto POST intuitivamente è pensato per la creazione di una nuova risorsa, mentre PUT è necessario per l'aggiornamento della risorsa già esistente.

Alcuni potrebbero pensare che gli aggiornamenti possano essere eseguiti con POST. Non esiste una regola rigida quale utilizzare per gli aggiornamenti o quale creare per creare. Anche in questo caso si tratta di convenzioni e intuitivamente sono propenso al ragionamento sopra menzionato e lo seguo.


6
per PUT è simile alla query INSERT o UPDATE
Eugen Konkov,

1
effettivamente PUT Puoi pensare a un simile a "UPDATE STUDENT SET address =" abc "dove id =" 123 "; sarebbe un'istruzione per PATCH." UPDATE STUDENT SET address = "abc", name = "newname" dove id = " 123 "sarebbe un'analogia corretta per PUT
mko il

Put potrebbe essere utilizzato anche per INSERT. Ad esempio, se il tuo server ha rilevato che stavi tentando di caricare lo stesso file più volte, la tua richiesta sarebbe idempotente. (Non vengono effettuati nuovi caricamenti di file).
kiwicomb123,

43

POST è come pubblicare una lettera in una casella di posta o pubblicare un'e-mail in una coda di posta elettronica. PUT è come quando metti un oggetto in un buco cubby o un posto su uno scaffale (ha un indirizzo noto).

Con POST, stai postando all'indirizzo della CODA o della COLLEZIONE. Con PUT, ti stai rivolgendo all'indirizzo dell'ITEM.

PUT è idempotente. Puoi inviare la richiesta 100 volte e non importa. Il POST non è idempotente. Se invii la richiesta 100 volte, riceverai 100 e-mail o 100 lettere nella tua casella postale.

Una regola generale: se conosci l'id o il nome dell'articolo, usa PUT. Se si desidera che l'id o il nome dell'articolo vengano assegnati dalla parte ricevente, utilizzare POST.

POST vs. PUT


1
No, PUT implica che conosci l'URL. Se conosci solo l'ID, allora POST con quell'ID per ottenere l'URL.
Joshcodes,

6
L'id fa parte dell'URL, quindi sì, usa PUT se conosci l'URL (che include l'id).
Homer6

No, l'URL è determinato dal server e l'ID non fa necessariamente parte dell'URL. Roy Fielding ti direbbe lo stesso o potresti leggere la sua tesi .
Joshcodes,

@Joshcodes, supponendo che REST? In un'architettura RESTful, l'id oggetto fa sicuramente parte dell'URL, come in: / people / 123. Mi piace questo sito per REST: microformats.org/wiki/rest/urls
Beez,

1
@Beez il link mircoformats suggerisce un buon modo per i server di strutturare i loro URL ma il server determina l'URL. Il client non lo fa quasi mai. Vedi la mia risposta o l' articolo associato se non lo capisci.
Joshcodes

39

Nuova risposta (ora che ho capito meglio REST):

PUT è semplicemente una dichiarazione del contenuto che il servizio dovrebbe, d'ora in poi, utilizzare per rendere rappresentazioni della risorsa identificata dal client; POST è una dichiarazione del contenuto che il servizio dovrebbe, d'ora in poi, contenere (possibilmente duplicato) ma spetta al server come identificarlo.

PUT x(se xidentifica una risorsa ): "Sostituisci il contenuto della risorsa identificato da xcon il mio contenuto."

PUT x(se xnon identifica una risorsa): "Crea una nuova risorsa contenente il mio contenuto e usalo xper identificarlo."

POST x: "Conserva il mio contenuto e dammi un identificatore che posso usare per identificare una risorsa (vecchia o nuova) contenente tale contenuto (possibilmente mescolata con altro contenuto). Detta risorsa dovrebbe essere identica o subordinata a quella che xidentifica." " La risorsa di y è subordinata alla risorsa di x " è tipicamente ma non necessariamente implementata trasformando in y un sottotraccia di x (ad es. x = /fooe y = /foo/bar) e modificando la rappresentazione o le rappresentazioni della risorsa di x per riflettere l'esistenza di una nuova risorsa, ad esempio con un collegamento ipertestuale a yrisorsa e alcuni metadati. Solo quest'ultimo è davvero essenziale per una buona progettazione, poiché gli URL sono opachi in REST - dovresti usare hypermedia invece della costruzione di URL sul lato client per attraversare comunque il servizio.

In REST non esiste una risorsa contenente "contenuto". Mi riferisco come "contenuto" ai dati che il servizio utilizza per rendere le rappresentazioni in modo coerente. In genere è costituito da alcune righe correlate in un database o in un file (ad esempio un file di immagine). Spetta al servizio convertire il contenuto dell'utente in qualcosa che il servizio può utilizzare, ad esempio convertendo un payload JSON in istruzioni SQL.

Risposta originale (potrebbe essere più facile da leggere) :

PUT /something(se /somethingesiste già): "Prendi quello che hai /somethinge sostituiscilo con quello che ti do."

PUT /something(se /somethingnon esiste già): "Prendi ciò che ti do e mettilo a /something."

POST /something: "Prendi quello che ti do e mettilo dove vuoi /somethingfino a quando mi dai il suo URL quando hai finito."


Ma come puoi usare PUT per creare una nuova risorsa se non esiste, mentre il tuo metodo di generazione ID è su Incremento automatico? Di solito ORM genera automaticamente l'ID per te, come ad esempio il modo in cui vuoi che sia in un POST. Vuol dire che se vuoi implementare PUT nel modo giusto devi cambiare la tua generazione automatica dell'id? Questo è imbarazzante se la risposta è sì.
Roni Axelrad,

1
@RoniAxelrad: PUT è come un'istruzione "INSERT OR UPDATE" del database in cui si include la chiave nell'istruzione, quindi applicabile solo dove non è possibile garantire alcuna collisione. per esempio. il tuo dominio ha una "chiave naturale" o usi una guida. Il POST è come l'inserimento in una tabella con una chiave di incremento automatico. Il database deve indicare quale ID ha ottenuto dopo che è stato inserito. Nota che il tuo "INSERISCI O AGGIORNA" sostituirà qualsiasi dato precedente se esistesse.
Nigel Thorne,

@NigelThorne Grazie per la risposta. Quindi, se per esempio sto provando a mettere un ID libro 10 con un URI: PUT books / 10. Se l'ID libro 10 non esiste, dovrei creare un libro con ID 10 giusto? ma non riesco a controllare il numeratore dell'ID creazione, perché è l'incremento automatico. cosa dovrei fare in quella situazione?
Roni Axelrad,

1
@RoniAxelrad REST PUT a un ID che non esiste è una richiesta al server per creare una risorsa. Spetta ancora al server decidere se lo desidera. Il server è responsabile. Può rispondere con "No. Non ho intenzione di farlo". Lo fai già se l'utente non dispone di autorizzazioni sufficienti ... ecc. Va bene per il server dire "No". REST è una convenzione che ci consente di definire il significato di vari tipi di richiesta ... il tuo server decide cosa fare con quelle richieste in base alla tua logica aziendale :) Anche se dice "no" sta ancora seguendo REST :)
Nigel Thorne

38

Risposta breve:

Semplice regola empirica: utilizzare POST per creare, utilizzare PUT per l'aggiornamento.

Risposta lunga:

INVIARE:

  • POST viene utilizzato per inviare dati al server.
  • Utile quando l'URL della risorsa è sconosciuto

METTERE:

  • PUT viene utilizzato per trasferire lo stato sul server
  • Utile quando è noto l'URL di una risorsa

Risposta più lunga:

Per capirlo, dobbiamo chiederci perché fosse richiesto il PUT, quali fossero i problemi che il PUT stava cercando di risolvere e che il POST non ha potuto risolvere.

Dal punto di vista di un'architettura REST non c'è nulla che conta. Avremmo potuto vivere anche senza PUT. Ma dal punto di vista dello sviluppatore di un cliente ha reso la sua vita molto più semplice.

Prima di PUT, i client non erano in grado di conoscere direttamente l'URL generato dal server o se tutto ciò ne avesse generato o se i dati da inviare al server fossero già aggiornati o meno. PUT ha sollevato lo sviluppatore di tutti questi mal di testa. PUT è idempotente, PUT gestisce le condizioni di gara e PUT consente al client di scegliere l'URL.


3
La tua breve risposta potrebbe essere MOLTO sbagliata. HTTP PUT è libero di essere ripetuto dai proxy HTTP. E quindi, se PUT sta effettivamente eseguendo SQL INSERT, potrebbe non riuscire la seconda volta, il che significa che restituirà risultati diversi e quindi non sarebbe IDEMPOTENT (che è la differenza tra PUT e POST)
Kamil Tomšík,

36

Ruby on Rails 4.0 utilizzerà il metodo "PATCH" anziché PUT per eseguire aggiornamenti parziali.

RFC 5789 dice di PATCH (dal 1995):

È necessario un nuovo metodo per migliorare l'interoperabilità e prevenire errori. Il metodo PUT è già definito per sovrascrivere una risorsa con un nuovo corpo completo e non può essere riutilizzato per apportare modifiche parziali. Altrimenti, i proxy e le cache, e anche i client e i server, potrebbero confondersi sul risultato dell'operazione. Il POST è già utilizzato ma senza ampia interoperabilità (per uno, non esiste un modo standard per scoprire il supporto del formato patch). PATCH era menzionato nelle specifiche HTTP precedenti, ma non completamente definito.

" Edge Rails: PATCH è il nuovo metodo HTTP primario per gli aggiornamenti ", spiega.


27

A rischio di riaffermare ciò che è già stato detto, sembra importante ricordare che PUT implica che il client controlla ciò che l' URL finirà per essere, durante la creazione di una risorsa. Quindi parte della scelta tra PUT e POST riguarderà quanto puoi fidarti del client per fornire URL corretti e normalizzati coerenti con qualunque sia il tuo schema URL.

Quando non puoi fidarti completamente del client per fare la cosa giusta, sarebbe più appropriato usare POST per creare un nuovo elemento e quindi inviare l'URL al client nella risposta.


2
Sono un po 'in ritardo per questo - ma qualcuno che dice qualcosa di simile su un altro sito web ha fatto clic per me. Se stai creando una risorsa e stai utilizzando un ID auto-incrementato come "identificatore" anziché un nome assegnato all'utente, dovrebbe essere un POST.
Ixmatus,

2
Questo non è giusto - PUT può ancora creare una risorsa facendo riferimento ad essa con un nome non canonico, a patto che nella risposta, il server restituisce un Locationheader che non contiene il nome della risorsa canonica.
Ether

1
@Joshcodes non dimenticare che puoi avere molti URI che fanno riferimento alla stessa risorsa sottostante. Quindi quello che Ether ha detto è un buon consiglio, il client può mettere un URL (che potrebbe essere più semantico, come PUT /X-files/series/4/episodes/max) e il server risponde con un URI che fornisce un breve link univoco canonico a quella nuova risorsa (cioè /X-Ffiles/episodes/91)
thecoshman

@thecoshman il problema è che la struttura URL non appartiene al client. Leggere sull'auto-scoperta (anche parte di REST) ​​può aiutare a chiarire questo.
Joshcodes

@Joshcodes quindi con quella logica, un client non dovrebbe mai usare PUT per creare in quanto non dovrebbe preoccuparsi di fornire l'URL. Bene ... a meno che il server non abbia fornito un URL a PUT a se il client vuole utilizzarlo ... qualcosa come "PUT / commenti / nuovo" e il server potrebbe rispondere "204 / commenti / 234532" ma sembra un po ' RPC per me, il cliente dovrebbe solo POST / commenti ...
thoshoshman il

24

In un modo molto semplice sto prendendo l'esempio della sequenza temporale di Facebook.

Caso 1: quando pubblichi qualcosa sulla tua cronologia, si tratta di una nuova voce nuova. Quindi in questo caso usano il metodo POST perché il metodo POST non è idempotente.

Caso 2: se il tuo amico commenta il tuo post per la prima volta, anche questo creerà una nuova voce nel database in modo da utilizzare il metodo POST.

Caso 3: se il tuo amico modifica il suo commento, in questo caso, aveva un ID commento, quindi aggiornerà un commento esistente invece di creare una nuova voce nel database. Pertanto per questo tipo di operazione utilizzare il metodo PUT perché è idempotente. *

In una sola riga, utilizzare POST per aggiungere una nuova voce nel database e PUT per aggiornare qualcosa nel database.


4
Se il commento è un oggetto con proprietà come ID utente, data di creazione, messaggio di commento, ecc. E al momento della modifica viene aggiornato solo il messaggio di commento, PATCH deve essere eseguito qui?
Habeeb Perwad,

PUT viene utilizzato da FB per aggiornare il commento perché viene aggiornata una risorsa esistente, ed è quello che fa PUT (aggiorna una risorsa). PUT sembra essere idempotente, in contrasto con POST. Un verbo HTTP essendo idempotente influisce sulla gestione degli errori ma non ne determina l'utilizzo. Vedere la mia risposta per un maggiore dettaglio spiegazione: stackoverflow.com/questions/630453/put-vs-post-in-rest/...
Joshcodes

21

La considerazione più importante è l' affidabilità . Se si perde un messaggio POST, lo stato del sistema non è definito. Il recupero automatico è impossibile. Per i messaggi PUT, lo stato non è definito solo fino al primo tentativo riuscito.

Ad esempio, potrebbe non essere una buona idea creare transazioni con carta di credito con POST.

Se ti capita di avere URI generati automaticamente sulla tua risorsa, puoi comunque usare PUT passando un URI generato (che punta a una risorsa vuota) al client.

Alcune altre considerazioni:

  • POST invalida le copie memorizzate nella cache dell'intera risorsa contenente (migliore coerenza)
  • Le risposte PUT non sono memorizzabili nella cache mentre quelle POST (Richiedi contenuto-posizione e scadenza)
  • PUT è meno supportato ad esempio da Java ME, browser meno recenti, firewall

Questo non è corretto Per POST, anche lo stato non è definito solo fino al primo tentativo riuscito. Quindi, il server accetta il POST (il messaggio non è mai arrivato), genera un conflitto 409 per un ID duplicato (messaggio arrivato, la risposta è andata persa) o qualsiasi altra risposta valida.
Joshcodes

In generale, un useragent non sarebbe in grado di riprovare in sicurezza l'operazione POST poiché l'operazione POST non garantisce che due operazioni abbiano lo stesso effetto di una. Il termine "ID" non ha nulla a che fare con HTTP. L'URI identifica la risorsa.
Hans Malherbe,

Un useragent può "riprovare" in modo sicuro un'operazione POST tutte le volte che lo desidera. Riceverà solo un errore ID duplicato (supponendo che la risorsa abbia un ID) o un errore dati duplicato (supponendo che si tratti di un problema e che la risorsa non abbia ID).
Joshcodes,

Colpisce la testa contro il muro. HTTP non ha una soluzione al problema dell'affidabilità, e questo non è ben compreso, non molto discusso e semplicemente non soddisfatto nella stragrande maggioranza delle applicazioni web. @Joshcodes Ho una risposta a questa domanda. Sono sostanzialmente d'accordo con Hans. C'è un problema.
bbsimonbb,

@bbsimonbb, HTTP ha una serie solida e ben documentata di risposte agli errori. La mia risposta a questa domanda ( stackoverflow.com/questions/630453/put-vs-post-in-rest/… ) spiega come utilizzare http in base alle specifiche per ottenere coerenza.
Joshcodes,

17

I lettori che non conoscono questo argomento saranno colpiti dalla discussione infinita su cosa dovresti fare e dalla relativa assenza di lezioni dall'esperienza. Il fatto che il REST sia "preferito" rispetto al SOAP è, suppongo, un apprendimento di alto livello dall'esperienza, ma per fortuna dobbiamo essere progrediti da lì? È il 2016. La tesi di dottorato di Roy è stata nel 2000. Cosa abbiamo sviluppato? Era divertente? È stato facile integrarsi con? Supportare? Gestirà l'ascesa di smartphone e connessioni mobili traballanti?

Secondo ME, le reti della vita reale non sono affidabili. Timeout delle richieste. Le connessioni vengono ripristinate. Le reti si interrompono per ore o giorni alla volta. I treni entrano nei tunnel con gli utenti mobili a bordo. Per ogni data richiesta (come occasionalmente riconosciuto in tutta questa discussione) la richiesta può cadere nell'acqua sulla sua strada, oppure la risposta può cadere nell'acqua sulla via del ritorno. In queste condizioni, l'invio di richieste PUT, POST e DELETE direttamente contro risorse sostanziali mi ha sempre sembrato un po 'brutale e ingenuo.

HTTP non fa nulla per garantire il completamento affidabile della richiesta-risposta, e va bene perché questo è correttamente il lavoro delle applicazioni sensibili alla rete. Sviluppando una tale applicazione, puoi saltare attraverso i cerchi per usare PUT invece di POST, quindi più cerchi per dare un certo tipo di errore sul server se rilevi richieste duplicate. Di nuovo al cliente, devi saltare attraverso i cerchi per interpretare questi errori, recuperare, riconvalidare e ripubblicare.

Oppure puoi farlo : considera le tue richieste non sicure come risorse effimere per singolo utente (chiamiamole azioni). I clienti richiedono una nuova "azione" su una risorsa sostanziale con un POST vuoto alla risorsa. POST verrà utilizzato solo per questo. Una volta in modo sicuro in possesso dell'URI dell'azione appena coniata, il client METTE la richiesta non sicura all'URI dell'azione, non la risorsa di destinazione . Risolvere l'azione e aggiornare la risorsa "reale" è correttamente il lavoro dell'API ed è qui disaccoppiato dalla rete inaffidabile.

Il server svolge l'attività, restituisce la risposta e la memorizza rispetto all'URI dell'azione concordato . Se qualcosa va storto, il client ripete la richiesta (comportamento naturale!) E se il server l'ha già vista, ripete la risposta memorizzata e non fa nient'altro .

Individuerai rapidamente la somiglianza con le promesse: creiamo e restituiamo il segnaposto per il risultato prima di fare qualsiasi cosa. Anche come una promessa, un'azione può avere successo o fallire una volta, ma il suo risultato può essere recuperato ripetutamente.

Soprattutto, diamo la possibilità di inviare e ricevere applicazioni per collegare l'azione identificata in modo univoco all'unicità nei rispettivi ambienti. E possiamo iniziare a chiedere e far rispettare! Comportamento responsabile dei clienti: ripeti le tue richieste quanto vuoi, ma non andare a generare una nuova azione finché non sei in possesso di un risultato definitivo da quello esistente.

Pertanto, numerosi problemi spinosi scompaiono. Le richieste di inserimento ripetute non creano duplicati e non creiamo la vera risorsa finché non siamo in possesso dei dati. (le colonne del database possono rimanere non annullabili). Le richieste di aggiornamento ripetute non colpiranno stati incompatibili e non sovrascriveranno le modifiche successive. I clienti possono (ri) recuperare ed elaborare senza problemi la conferma originale per qualsiasi motivo (client bloccato, risposta mancante, ecc.).

Le richieste di eliminazione successive possono visualizzare ed elaborare la conferma originale, senza colpire un errore 404. Se le cose impiegano più tempo del previsto, possiamo rispondere in via provvisoria e abbiamo un posto dove il cliente può ricontrollare per il risultato definitivo. La parte più bella di questo modello è la sua proprietà Kung-Fu (Panda). Prendiamo un punto debole, la propensione per i clienti a ripetere una richiesta ogni volta che non capiscono la risposta e la trasformiamo in un punto di forza :-)

Prima di dirmi che questo non è RESTful, ti preghiamo di considerare i numerosi modi in cui i principi REST sono rispettati. I clienti non costruiscono URL. L'API rimane rilevabile, sebbene con un piccolo cambiamento nella semantica. I verbi HTTP sono usati in modo appropriato. Se pensi che questo sia un cambiamento enorme da implementare, posso dirti per esperienza che non lo è.

Se pensi di avere enormi quantità di dati da archiviare, parliamo di volumi: una tipica conferma di aggiornamento è una frazione di un kilobyte. HTTP ti dà attualmente un minuto o due per rispondere in modo definitivo. Anche se memorizzi azioni solo per una settimana, i clienti hanno ampie possibilità di recuperare. Se si dispone di volumi molto elevati, è possibile che si desideri un archivio valori chiave dedicato conforme agli acidi o una soluzione in memoria.


1
Memorizzare la risposta sarà come mantenere una sessione? Ciò causerebbe problemi di ridimensionamento (orizzontale).
Saurabh Harwande,

17

Oltre alle differenze suggerite da altri, voglio aggiungerne uno in più.

Nel metodo POST è possibile inviare i parametri del corpo inform-data

Nel metodo PUT devi inviare i parametri del corpox-www-form-urlencoded

Intestazione Content-Type:application/x-www-form-urlencoded

Di conseguenza, non è possibile inviare file o dati multipart nel metodo PUT

MODIFICARE

Il tipo di contenuto "application / x-www-form-urlencoded" non è efficace per l'invio di grandi quantità di dati binari o testo contenente caratteri non ASCII. Il tipo di contenuto "multipart / form-data" deve essere utilizzato per l'invio di moduli che contengono file, dati non ASCII e dati binari.

Ciò significa che devi inviare

file, dati non ASCII e dati binari

dovresti usare il metodo POST


3
Perché questo non è stato votato? Se vero, questa è una distinzione critica, vero?
Iofacture,

2
L'ho affrontato durante l'implementazione dell'API per l'aggiornamento del profilo, che include il caricamento delle foto del profilo utente. Poi l'ho provato con il postino, Ajax, PHP curl e laravel 5.6 come backend.
Rohit Dhiman,

14

Sembra esserci sempre un po 'di confusione su quando utilizzare il POST HTTP rispetto al metodo PUT HTTP per i servizi REST. La maggior parte degli sviluppatori proverà ad associare le operazioni CRUD direttamente ai metodi HTTP. Sosterrò che questo non è corretto e non si può semplicemente associare i concetti CRUD ai metodi HTTP. Questo è:

Create => HTTP PUT
Retrieve => HTTP GET
Update => HTTP POST
Delete => HTTP DELETE

È vero che R (etrieve) e D (elete) delle operazioni CRUD possono essere mappati direttamente ai metodi HTTP GET e DELETE rispettivamente. Tuttavia, la confusione sta nelle operazioni C (reate) e U (update). In alcuni casi, è possibile utilizzare il PUT per una creazione, mentre in altri casi sarà richiesto un POST. L'ambiguità sta nella definizione di un metodo PUT HTTP rispetto a un metodo POST HTTP.

Secondo le specifiche HTTP 1.1, i metodi GET, HEAD, DELETE e PUT devono essere idempotenti e il metodo POST non è idempotente. Vale a dire che un'operazione è idempotente se può essere eseguita su una risorsa una o più volte e restituire sempre lo stesso stato di quella risorsa. Considerando che un'operazione non idempotente può restituire uno stato modificato della risorsa da una richiesta all'altra. Quindi, in un'operazione non idempotente, non vi è alcuna garanzia che si riceverà lo stesso stato di una risorsa.

Sulla base della definizione idempotente di cui sopra, la mia opinione sull'uso del metodo HTTP PUT rispetto all'utilizzo del metodo HTTP POST per i servizi REST è: Utilizzare il metodo HTTP PUT quando:

The client includes all aspect of the resource including the unique identifier to uniquely identify the resource. Example: creating a new employee.
The client provides all the information for a resource to be able to modify that resource.This implies that the server side does not update any aspect of the resource (such as an update date).

In entrambi i casi, queste operazioni possono essere eseguite più volte con gli stessi risultati. Cioè la risorsa non verrà modificata richiedendo l'operazione più di una volta. Quindi, una vera operazione idempotente. Utilizzare il metodo POST HTTP quando:

The server will provide some information concerning the newly created resource. For example, take a logging system. A new entry in the log will most likely have a numbering scheme which is determined on the server side. Upon creating a new log entry, the new sequence number will be determined by the server and not by the client.
On a modification of a resource, the server will provide such information as a resource state or an update date. Again in this case not all information was provided by the client and the resource will be changing from one modification request to the next. Hence a non idempotent operation.

Conclusione

Non correlare direttamente e mappare le operazioni CRUD ai metodi HTTP per i servizi REST. L'uso di un metodo PUT HTTP rispetto a un metodo POST HTTP dovrebbe essere basato sull'aspetto idempotente di tale operazione. Cioè, se l'operazione è idempotente, utilizzare il metodo HTTP PUT. Se l'operazione non è idempotente, utilizzare il metodo POST HTTP.


2
Update => HTTP POST: POST non è per l'aggiornamento
Premraj

@premraj Hai supposto che Burhan ti stesse dicendo di non fare; vale a dire, stai combinando CRUD, REST e HTTP. Se leggi RFC 7231, dove sono definite queste cose, scoprirai che nel protocollo HTTP, la definizione di POST consente certamente l'aggiornamento. Sono solo i vincoli di REST che dicono diversamente.
IAM_AL_X

13

il server di origine può creare la risorsa con quell'URI

Quindi usi POST e probabilmente, ma non necessario, PUT per la creazione di risorse. Non devi supportare entrambi. Per me il POST è perfettamente perfetto. Quindi è una decisione di progettazione.

Come indicato nella citazione, si utilizza PUT per la creazione di una risorsa non assegnata a un IRI e si desidera comunque creare una risorsa. Ad esempio, di PUT /users/123/passwordsolito sostituisce la vecchia password con una nuova, ma è possibile utilizzarla per creare una password se non esiste già (ad esempio, da utenti appena registrati o ripristinando utenti vietati).


Penso che tu sia riuscito a fornire uno dei pochi buoni esempi di come usare PUT, ben fatto.
thecoshman,

12

Atterrerò con il seguente:

PUT si riferisce a una risorsa, identificata dall'URI. In questo caso, lo stai aggiornando. È la parte dei tre verbi che si riferiscono alle risorse: cancella e diventa gli altri due.

POST è fondamentalmente un messaggio in formato libero, con il suo significato definito "fuori banda". Se il messaggio può essere interpretato come l'aggiunta di una risorsa a una directory, sarebbe OK, ma in pratica è necessario comprendere il messaggio che si sta inviando (postare) per sapere cosa accadrà con la risorsa.


Poiché PUT, GET e DELETE si riferiscono a una risorsa, sono anche per definizione idempotenti.

POST può svolgere le altre tre funzioni, ma la semantica della richiesta andrà persa sugli intermediari come cache e proxy. Questo vale anche per fornire sicurezza sulla risorsa, poiché l'URI di un post non indica necessariamente la risorsa a cui si sta applicando (può però).

Un PUT non deve necessariamente essere un creare; il servizio potrebbe errori se la risorsa non è già stata creata, ma in caso contrario aggiornarla. O viceversa: può creare la risorsa, ma non consentire aggiornamenti. L'unica cosa richiesta per PUT è che punta a una risorsa specifica e il suo payload è la rappresentazione di quella risorsa. Un PUT riuscito significa (escludendo l'interferenza) che un GET recuperi la stessa risorsa.


Modifica: un'altra cosa - un PUT può creare, ma se lo fa, l'ID deve essere un ID naturale - AKA un indirizzo e-mail. In questo modo quando metti due volte, il secondo put è un aggiornamento del primo. Questo lo rende idempotente .

Se viene generato l'ID (un nuovo ID dipendente, ad esempio), il secondo PUT con lo stesso URL creerebbe un nuovo record, il che viola la regola idempotente. In questo caso il verbo sarebbe POST e il messaggio (non risorsa) sarebbe quello di creare una risorsa usando i valori definiti in questo messaggio.


9

La semantica dovrebbe essere diversa, in quanto "PUT", come "GET", dovrebbe essere idempotente - il che significa che puoi richiedere la stessa richiesta PUT più volte e il risultato sarà come se l'avessi eseguita una sola volta.

Descriverò le convenzioni che ritengo siano le più utilizzate e le più utili:

Quando inserisci una risorsa in un determinato URL, ciò che accade è che deve essere salvato in quell'URL o qualcosa del genere.

Quando pubblichi una risorsa in corrispondenza di un determinato URL, spesso pubblichi un'informazione relativa a tale URL. Ciò implica che la risorsa nell'URL esiste già.

Ad esempio, quando si desidera creare un nuovo flusso, è possibile inserirlo in qualche URL. Ma quando vuoi POST un messaggio a uno stream esistente, POST al suo URL.

Per quanto riguarda la modifica delle proprietà dello stream, puoi farlo con PUT o POST. Fondamentalmente, usa "PUT" solo quando l'operazione è idempotente, altrimenti usa POST.

Si noti, tuttavia, che non tutti i browser moderni supportano verbi HTTP diversi da GET o POST.


Quello che descrivi POST è in realtà come dovrebbe comportarsi PATCH. POST dovrebbe significare qualcosa di più simile a "aggiungere" come in "posta nella mailing list".
Alexander Torstling,

8

Il più delle volte li userete in questo modo:

  • POST una risorsa in una raccolta
  • PUT una risorsa identificata da collection /: id

Per esempio:

  • POST / articoli
  • PUT / items / 1234

In entrambi i casi, il corpo della richiesta contiene i dati per la risorsa da creare o aggiornare. Dovrebbe essere ovvio dai nomi delle rotte che POST non è idempotente (se lo chiamate 3 volte creerà 3 oggetti), ma PUT è idempotente (se lo chiamate 3 volte il risultato è lo stesso). PUT viene spesso utilizzato per l'operazione "upsert" (creazione o aggiornamento), ma è sempre possibile restituire un errore 404 se si desidera utilizzarlo solo per modificarlo.

Si noti che POST "crea" un nuovo elemento nella raccolta e PUT "sostituisce" un elemento in un determinato URL, ma è una pratica molto comune utilizzare PUT per modifiche parziali, ovvero utilizzarlo solo per aggiornare le risorse esistenti e modifica solo i campi inclusi nel corpo (ignorando gli altri campi). Ciò è tecnicamente errato, se si desidera essere puristi di REST, PUT dovrebbe sostituire l'intera risorsa e utilizzare PATCH per l'aggiornamento parziale. Personalmente non mi interessa molto nella misura in cui il comportamento è chiaro e coerente su tutti i tuoi endpoint API.

Ricorda, REST è un insieme di convenzioni e linee guida per rendere semplice la tua API. Se si finisce con un aggirare complicato solo per selezionare la casella "RESTfull", allora si sta sconfiggendo lo scopo;)


7

Sebbene esista probabilmente un modo agnostico per descriverli, sembra essere in conflitto con varie dichiarazioni dalle risposte ai siti Web.

Siamo molto chiari e diretti qui. Se sei uno sviluppatore .NET che lavora con l'API Web, i fatti sono (dalla documentazione dell'API Microsoft), http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web -api-that-supporta-crud-operazioni :

1. PUT = UPDATE (/api/products/id)
2. MCSD Exams 2014 -  UPDATE = PUT, there are **NO** multiple answers for that question period.

Sicuramente "puoi" usare "POST" per l'aggiornamento, ma segui semplicemente le convenzioni stabilite per te con la tua struttura. Nel mio caso è .NET / Web API, quindi PUT è per AGGIORNAMENTO non c'è dibattito.

Spero che questo aiuti tutti gli sviluppatori Microsoft che leggono tutti i commenti con i collegamenti ai siti Web Amazon e Sun / Java.


7

Ecco una semplice regola:

PUT to a URL dovrebbe essere usato per aggiornare o creare la risorsa che può essere localizzata a quell'URL.

Il POST di un URL deve essere utilizzato per aggiornare o creare una risorsa che si trova su un altro URL ("subordinato") o che non è localizzabile tramite HTTP.


1
PUT non è per l'aggiornamento, è per la sostituzione, notare che per creare non si sostituisce nulla con qualcosa. POST non è assolutamente da aggiornare in nessuna forma.
thecoshman,

2
Lo dice la specifica http? O stai basando il tuo commento su qualcos'altro?
Adam Griffiths,

È solo buonsenso, come aggiorni qualcosa quando non sai cosa stai aggiornando? POST è per la creazione di una nuova risorsa.
thecoshman,

2
thecoshman - stai abusando della semantica qui - una sostituzione può essere un aggiornamento se è la stessa risorsa con alcune differenze. Una sostituzione è valida solo per put se si sostituisce la stessa risorsa. La sostituzione con una risorsa nuova e diversa non è valida (rimuovere vecchia e aggiungere nuova?), Soprattutto se la "nuova" risorsa non ha un ID naturale. POST, OTOH, è qualcosa che può creare, aggiornare, sostituire ed eliminare - l'utilizzo di post dipende dalla presenza o meno di un messaggio da interpretare, come "applica lo sconto", che può o meno modificare la risorsa in base a logica.
Gerard ONeill,

Per quanto riguarda il tuo secondo commento, che ne dici di "ottenere" la risorsa, modificare i campi necessari e quindi rimetterla? Oppure che ne dite se la risorsa proviene da una fonte diversa ma utilizza un ID naturale (ID esterno) - put aggiorna naturalmente la risorsa all'URL quando i dati originali vengono modificati.
Gerard ONeill,

6

Se hai familiarità con le operazioni del database, ci sono

  1. Selezionare
  2. Inserire
  3. Aggiornare
  4. Elimina
  5. Unisci (aggiorna se già esistente, altrimenti inserisci)

Uso PUTper Unisci e aggiorno come operazioni e utilizzo POSTper Inserimenti.


5

In pratica, POST funziona bene per la creazione di risorse. L'URL della risorsa appena creata deve essere restituito nell'intestazione della risposta della posizione. PUT dovrebbe essere usato per aggiornare completamente una risorsa. Si prega di comprendere che queste sono le migliori pratiche durante la progettazione di un'API RESTful. Le specifiche HTTP in quanto tali non limitano l'utilizzo di PUT / POST con alcune restrizioni per la creazione / l'aggiornamento delle risorse. Dai un'occhiata a http://techoctave.com/c7/posts/71-twitter-rest-api-dissected che sintetizza le migliori pratiche.


Per la maggior parte, leggendo tutto questo rumore, sembri sulla palla. Direi però che dovremmo fare riferimento a PUT come metodo di sostituzione, piuttosto che a creare / aggiornare. Penso che descriva meglio in uno cosa fa.
thecoshman,
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.