Includere un ID risorsa nel payload o derivare dall'URI


13

Nel progettare un'API, ci siamo posti la questione se un payload PUT dovesse contenere l'ID della risorsa da aggiornare.

Questo è ciò che attualmente abbiamo:

PUT /users/123 Payload: {name: "Adrian"}

Il nostro codice di percorso estrae l'ID dall'URI e continua con l'aggiornamento.

I primi utenti della nostra API si chiedono perché non consentiamo l'ID nel payload:

PUT /users/123 Payload: {id: 123, name: "Adrian"}

Il motivo per cui non l'abbiamo permesso è perché l'ID è duplicato, nel payload e nell'URI.

Pensando ancora a questo, stiamo associando la risorsa all'URI.

Se l'URI non ha l'ID, il payload dovrà essere modificato:

PUT /no/id/here Payload: {name: "Adrian"} < What user???

Ci sono dei motivi per non farlo?

Risposte:


14

Si sono suppone per accoppiare il Uniform Resource Identifier alla risorsa .

Quando REST è implementato con HTTP, si utilizza GET per recuperare il valore corrente della risorsa e PUT per impostare un nuovo valore. Il GET non ha un payload, quindi la risorsa deve essere identificata dall'URI. E il PUT viene logicamente eseguito nello stesso URI e il payload dovrebbe apparire esattamente come si desidera che il prossimo GET restituisca.

È possibile utilizzare POST con URI diversi, ma avrebbe meno senso in quanto sarebbe inutilmente asimmetrico rispetto al GET. Il POST per l'URI comune potrebbe avere senso solo per la creazione di nuove risorse ( POST /users/new, payload:, {name: "Adrian"}risposta {id: 345, name: "Adrian"}), ma questo non è idempotente e quindi dovrebbe essere evitato se stai lottando per il riposo¹. Invece dovresti riservare l'ID con una chiamata e quindi usare PUT per impostare il nuovo ID; questo è tollerante agli errori, perché se la prima richiesta fallisce, la prenotazione dell'ID può eventualmente PUTscadere ed è idempotente. Oppure usa l'UUID generato dal client.


¹ La definizione di REST non dice nulla sull'idempotenza, quindi non posso davvero affermare che non è REST se si hanno operazioni non idempotenti. Ciò non cambia il fatto che attenersi alle richieste idempotenti rende le cose più affidabili senza complicarle ed è quindi raccomandato.


3
Per quanto ne so, una richiesta POST non deve essere idempotente. Quindi non vedo alcun problema con la pubblicazione su /users(non è necessario aggiungere "nuovo").
lex82,

grazie per la tua risposta. Vedo che è una buona funzionalità avere idempotenza per tutte le richieste, ma chi dice che questo è necessario per un'API REST? Certamente molte API che si definiscono RESTful consentono richieste POST non idempotenti (specialmente quando il server genera ID per nuove risorse). Ma anche se applichi una definizione molto rigorosa di REST, non vedo quale vincolo architettonico venga violato con POST non idempotenti come nell'esempio sopra.
lex82,

Posso certamente immaginare le richieste POST che violano un vincolo. Semplicemente non vedo perché pubblicare una risorsa in una raccolta e lasciare che il server decida sul suo ID è una violazione dei vincoli REST.
lex82,


3
L'idea di POST non deve essere idempotente ....
EralpB

2

Pensando ancora a questo, stiamo associando la risorsa all'URI.

Se l'URI non ha l'ID, il payload dovrà essere modificato:

PUT / no / id / here Payload: {name: "Adrian"} <Quale utente ???

Ci sono dei motivi per non farlo?

La risposta a questa domanda dipende dal fatto se si desidera consentire al client di modificare l'ID?

Se il client può modificare l'ID, tramite un PUT, l'URI per la risorsa cambierà e dovresti fornire un 301 spostato in modo permanente ogni volta che una risorsa accede al vecchio URI.

Quindi, ad esempio, inizi con una risorsa in

/users/123

e il client inserisce quanto segue sulla risorsa

{id: 222, name: "Adrian"}

la risorsa è stata aggiornata e il suo URI lo è ora

/users/222

Il Locationcampo nella risposta PUT dovrebbe contenere il nuovo URI e, se ci vai /users/123, dovresti ottenere una 301risposta con il campo Posizione che punta alla nuova /users/222risorsa.

Nella maggior parte dei casi, tuttavia, in realtà non si desidera che il client sia in grado di modificare l'ID, in quanto ciò può diventare piuttosto disordinato abbastanza rapidamente. In tal caso l'ID è qualcosa che solo il server può modificare e dovresti lasciarlo fuori dal corpo PUT, poiché il client non può aggiornare questo stato.

Se hai richiesto un URI diverso sulla stessa risorsa, ad esempio

/users/adian_lync

quindi se quella risorsa non esiste, il server dovrebbe crearla e creare e ID quando lo sta facendo


1
Il motivo per cui abbiamo messo in dubbio il posizionamento dell'ID nel payload è dovuto al fatto che Backbone.js ha passato l'ID in una richiesta PUT per impostazione predefinita. Possiamo impedire che ciò accada, ma ora voglio sapere perché è il comportamento predefinito.
Adrian Lynch

1
Temo di non avere familiarità con Backbone.js. Sembra inutile se l'ID è incluso anche nell'URL. Forse una svista da parte degli sviluppatori
Cormac Mulhall,
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.