Crea richiesta con POST, con codici di risposta 200 o 201 e contenuto


125

Supponiamo che io scriva un servizio REST il cui intento è aggiungere un nuovo elemento di dati a un sistema.

Ho intenzione di POST a

http://myhost/serviceX/someResources

Supponiamo che funzioni, quale codice di risposta dovrei usare? E quale contenuto potrei restituire.

Sto esaminando le definizioni dei codici di risposta HTTP e vedo queste possibilità:

200: restituisce un'entità che descrive o contiene il risultato dell'azione;

201: che significa CREATO. Significato * La richiesta è stata soddisfatta e ha portato alla creazione di una nuova risorsa. La risorsa appena creata può essere referenziata dagli URI restituiti nell'entità della risposta, con l'URI più specifico per la risorsa fornito da un campo di intestazione Location. La risposta DOVREBBE includere un'entità contenente un elenco di caratteristiche della risorsa e posizioni da cui l'utente o il programma utente può scegliere quella più appropriata. Il formato dell'entità è specificato dal tipo di supporto fornito nel campo dell'intestazione Content-Type. *

Quest'ultimo suona più in linea con le specifiche Http, ma non mi è per niente chiaro cosa

La risposta DOVREBBE includere un'entità contenente un elenco delle caratteristiche delle risorse e delle posizioni

si intende.

Raccomandazioni? Interpretazioni?

Risposte:


78

L'idea è che il corpo della risposta ti dia una pagina che ti collega alla cosa:

201 Creato

Il codice di stato 201 (Creato) indica che la richiesta è stata soddisfatta e ha portato alla creazione di una o più nuove risorse. La risorsa primaria creata dalla richiesta viene identificata da un campo di intestazione Posizione nella risposta o, se non viene ricevuto alcun campo Posizione, dall'URI della richiesta effettiva.

Questo significa che si dovrebbe includere una Locationnella risposta di intestazione che dà l'URL dove è possibile trovare la nuova creazione cosa :

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597

Corpo di risposta

Quindi continuano a menzionare cosa dovresti includere nel corpo della risposta :

Il payload della risposta 201 in genere descrive e collega alle risorse create.

Per le persone che utilizzano il browser, dai loro qualcosa che possono guardare e fare clic per accedere alla loro risorsa appena creata:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: text/html

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

Se la pagina verrà utilizzata solo da un robot, ha senso che la risposta sia leggibile dal computer:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/xml

<createdResources>
   <questionID>1860645</questionID>
   <answerID>36373586</answerID>
   <primary>/a/36373586/12597</primary>
   <additional>
      <resource>http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586</resource>
      <resource>http://stackoverflow.com/a/1962757/12597</resource>
   </additional>
</createdResource>

Oppure, se preferisci:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/json

{ 
   "questionID": 1860645, 
   "answerID": 36373586,
   "primary": "/a/36373586/12597",
   "additional": [
      "http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586",
      "http://stackoverflow.com/a/36373586/12597"
   ]
}

La risposta dipende interamente da te; è arbitrariamente quello che vorresti.

Cache friendly

Infine c'è l'ottimizzazione che posso pre-memorizzare nella cache la risorsa creata (perché ho già il contenuto; l'ho appena caricato). Il server può restituire una data o ETag che posso memorizzare con il contenuto che ho appena caricato:

Vedere la Sezione 7.2 per una discussione sul significato e lo scopo dei campi di intestazione del validatore, come ETag e Last-Modified, in una risposta 201.

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/23704283/12597
Content-Type: text/html
ETag: JF2CA53BOMQGU5LTOQQGC3RAMV4GC3LQNRSS4
Last-Modified: Sat, 02 Apr 2016 12:22:39 GMT 

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

E ETagsono valori puramente arbitrari. Tutto ciò che conta è averli diversi quando una risorsa cambia (e le cache devono essere aggiornate). L'ETag è solitamente un hash (ad esempio SHA2). Ma può essere un database rowversiono un numero di revisione crescente. Qualunque cosa cambierà quando la cosa cambierà.


Finora la tua risposta sembra più sensata. Sono un po 'preoccupato per l'ontologia della risposta, ma a parte questo, sembra l'interpretazione più matura della specifica. Sono curioso di sapere se esiste un modo "reattivo" leggero per gestire l'output umano / macchina. ma soprattutto sono incuriosito dal tuo suggerimento di "memorizzare nella cache il tuo input". La maggior parte delle app Web che conosco non creerà una versione 1: 1 della risorsa. Anche se è qualcosa di banale come normalizzare le maiuscole di una stringa. Non è un po 'rischioso considerare la versione inviata come la versione contro cui è stato creato l'etichetta?
Anthony

1
@ Anthony, caching: potrebbe essere una specie di applicazione di archiviazione di file 1: 1. Confronta ad es. WebDAV PUT & POST. File enormi da gestire.
kxr

@Anthony Dipende da te se vuoi restituire un ETag al cliente. Se il contenuto che il client ha appena caricato non è quello che hai salvato, non restituire l'ETag. È la tua flessibilità e la tua scelta.
Ian Boyd

Perché nelle tue risposte manca la lunghezza del contenuto?
Vinnie Falco

1
@VinnieFalco Questa è una risposta sul codice di risposta 201. Content-Length è stato eliso per scopi espositivi.
Ian Boyd

91

Penso che l' API REST di atompub sia un ottimo esempio di servizio riposante. Vedi lo snippet di seguito dalle specifiche atompub:

POST /edit/ HTTP/1.1
Host: example.org
User-Agent: Thingio/1.0
Authorization: Basic ZGFmZnk6c2VjZXJldA==
Content-Type: application/atom+xml;type=entry
Content-Length: nnn
Slug: First Post

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
</entry>

Il server segnala una creazione riuscita con un codice di stato 201. La risposta include un'intestazione Posizione che indica l'URI della voce membro della voce Atom e una rappresentazione di quella voce nel corpo della risposta.

HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content-Length: nnn
Content-Type: application/atom+xml;type=entry;charset="utf-8"
Location: http://example.org/edit/first-post.atom
ETag: "c180de84f991g8"  

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
  <link rel="edit"
      href="http://example.org/edit/first-post.atom"/>
</entry>

La voce creata e restituita dalla raccolta potrebbe non corrispondere alla voce inviata dal cliente. Un server PUO 'modificare i valori di vari elementi nella Voce, come i valori atom: id, atom: updated e atom: author, e MAGGIO scegliere di rimuovere o aggiungere altri elementi e attributi, o modificare il contenuto dell'elemento e i valori degli attributi.


9
Restituire la risorsa creata potrebbe essere un po 'troppo, se la risorsa è nella grandezza dei gigabyte ...
Tor Valamo

10
Concordato! Questa è l'ottimizzazione della necessità, ma non vuoi farlo prematuramente. È importante progettare con spiriti riposanti e fare eccezioni solo quando sono necessarie.
Chandra Patni

3
@ChandraPatni, Atom è morto . Hai bisogno di esempi migliori.
Pacerier

16
Atom potrebbe essere morto, ma lo spirito dell'esempio è ancora perfetto.
Ashimema

2
La mia interpretazione originale della risposta 201 era più simile a "ehi, volevi creare una risorsa, ma in base al contesto, o non eri interessato al risultato finale oppure hai accesso in scrittura ma non in lettura a questa risorsa. In entrambi caso, tutto ciò di cui hai bisogno prima di tornare alla raccolta principale è l'URL della risorsa creata. A riprova che è stata creata. " Qualunque cosa oltre a ciò sembra essenzialmente una risposta 200. A meno che la RFC non avesse in mente qualcos'altro.
Anthony

50

In poche parole:

  • 200 quando un oggetto viene creato e restituito
  • 201 quando viene creato un oggetto ma viene restituito solo il suo riferimento (come un ID o un collegamento)

Fonte per questo?
sudo soul


3
Dopo aver letto tools.ietf.org/html/rfc7231#section-6.3.1 , sono d'accordo con questa comprensione - suppongo che ti stavo chiedendo di più come ci sei arrivato. Ma ora nella mia comprensione ... 200 = risorsa creata e restituita | 201 = risorsa creata e viene restituito il riferimento | 204 = risorsa creata e nessun payload restituito
sudo soul

34

Controlla HTTP: Definizioni dei metodi: POST .

L'azione eseguita dal metodo POST potrebbe non risultare in una risorsa che può essere identificata da un URI. In questo caso, 200 (OK) o 204 (Nessun contenuto) è lo stato della risposta appropriato, a seconda che la risposta includa o meno un'entità che descrive il risultato.

Se una risorsa è stata creata sul server di origine, la risposta DOVREBBE essere 201 (Created) e contenere un'entità che descrive lo stato della richiesta e fa riferimento alla nuova risorsa, e un'intestazione Location (vedere la sezione 14.30).


18

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19

È solo un valore-chiave delimitato da due punti.

ETag: "xyzzy"

Può essere qualsiasi tipo di dati di testo: generalmente includo una stringa JSON con l'identificatore dell'elemento creato. La facilità di test da sola rende utile includerlo.

ETag: "{ id: 1234, uri: 'http://domain.com/comments/1234', type: 'comment' }"

In questo esempio, l'identificatore, l'URI e il tipo dell'elemento creato sono le "caratteristiche e posizione della risorsa".


3
Stai dicendo che un ETag corrisponde a un'entità contenente un elenco di caratteristiche delle risorse e posizioni . Vedo che il tuo suggerimento è buono, molto d'accordo con il tuo punto di vista sui test. Tuttavia non vedo come questo si adatti a "un elenco di caratteristiche e posizioni delle risorse".
djna

L '"elenco delle caratteristiche e delle posizioni delle risorse" sarebbe il contenuto di qualsiasi struttura dati fornita. Un'implementazione più rigorosa sarebbe che la struttura JSON includesse l'uri della risorsa e forse il tipo di risorsa creata. Adatterò la risposta come tale.
tempire

7
Specifica i problemi, in modo che le persone possano imparare. Altrimenti, il commento è solo un gesto di saluto.
tempire

@SimonGibbs Quali problemi?
MEMark

2
Sebbene sia rigorosamente corretto secondo le specifiche, consiglia un'opzione di implementazione molto insolita. Inoltre non risponde effettivamente alla domanda nella parte superiore della pagina (oppure lo fa mescolando le parole ETag ed entità). La risposta con 43 voti è probabilmente migliore.
Simon Gibbs

1

L'output dipende effettivamente dal tipo di contenuto richiesto. Tuttavia, almeno dovresti mettere la risorsa che è stata creata in Posizione. Proprio come il modello Post-Redirect-Get.

Nel mio caso lo lascio vuoto fino a quando non viene richiesto diversamente. Poiché questo è il comportamento di JAX-RS quando si utilizza Response.created ().

Tuttavia, tieni presente che browser e framework come Angular non seguono automaticamente il 201. Ho notato il comportamento in http://www.trajano.net/2013/05/201-created-with-angular-resource/


-2

Un'altra risposta che avrei per questo sarebbe adottare un approccio pragmatico e mantenere semplice il tuo contratto API REST . Nel mio caso avevo refactoring la mia API REST per rendere le cose più testabili senza ricorrere a JavaScript o XHR, solo semplici moduli e collegamenti HTML.

Quindi, per essere più specifici sulla tua domanda sopra, userei semplicemente il codice di ritorno 200e farei in modo che il messaggio restituito contenga un messaggio JSON che la tua applicazione può capire. A seconda delle esigenze, potrebbe essere necessario l'ID dell'oggetto appena creato in modo che l'applicazione Web possa ottenere i dati in un'altra chiamata.

Una nota, nel mio contratto API refactoring, le risposte POST non dovrebbero contenere dati memorizzabili nella cache poiché i POST non sono realmente memorizzabili, quindi limitalo agli ID che possono essere richiesti e memorizzati nella cache utilizzando una richiesta GET.

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.