Modo RESTful per creare più elementi in una richiesta


122

Sto lavorando a un piccolo programma client server per raccogliere gli ordini. Voglio farlo in un modo "REST (ful)".

Quello che voglio fare è:

Raccogli tutte le linee d'ordine (prodotto e quantità) e invia l'ordine completo al server

Al momento vedo due opzioni per farlo:

  1. Invia ogni orderline al server: POST qty e product_id

In realtà non voglio farlo perché voglio limitare il numero di richieste al server, quindi l'opzione 2:

  1. Raccogli tutte le linee d'ordine e inviale subito al server.

Come devo implementare l'opzione 2? un paio di idee che ho sono: avvolgere tutte le orderline in un oggetto JSON e inviarlo al server o utilizzare un array per pubblicare le orderline.

È una buona idea o una buona pratica implementare l'opzione 2 e, in caso affermativo, come dovrei farlo.

Qual è la buona pratica?

rest  post 

Risposte:


74

Credo che un altro modo corretto di affrontare questo problema sarebbe creare un'altra risorsa che rappresenti la tua raccolta di risorse. Esempio, immagina di avere un endpoint come /api/sheep/{id}e possiamo POST /api/sheepper creare una risorsa pecora.

Ora, se vogliamo supportare la creazione di massa, dovremmo considerare una nuova risorsa per il gregge /api/flock(o /api/<your-resource>-collectionse ti manca un nome più significativo). Ricorda che le risorse non devono essere associate al database o ai modelli di app . Questo è un malinteso comune.

Le risorse sono una rappresentazione di livello superiore, non correlata ai tuoi dati. Operare su una risorsa può avere effetti collaterali significativi, come attivare un avviso per un utente, aggiornare altri dati correlati, avviare un processo di lunga durata, ecc. Ad esempio, potremmo mappare un file system o anche il pscomando unix come API REST.

Penso che sia lecito ritenere che gestire una risorsa possa anche significare la creazione di molte altre entità come effetto collaterale.


Sono d'accordo con questo. Dovresti astrarre il concetto di raccolta della tua risorsa e trattarlo come una risorsa. Questo ti darà maggiore flessibilità anche in futuro, quando vorrai iniziare a fare operazioni su questo ecc.
villy393

Questo è l'approccio giusto. Ciò non interrompe la richiesta di raccolta POST. Da allora, viene utilizzato per pubblicare una singola entità. L'invio di una richiesta in blocco con una "entità in blocco separata" è l'approccio giusto.
Sorter

2
Mi piaci così tanto il nome dell'endpoint api con pecore e gregge! Con un certo grado di astrazione ha quasi un riferimento biblico: "Ho altre pecore, che non sono di questo ovile; devo portare anche loro, e loro ascolteranno la mia voce; e diventeranno un solo gregge con un solo pastore". Giovanni 10:16.
Evgeny

1
È interessante notare che le persone consigliano di utilizzare la forma plurale (della raccolta) nell'URL quando si desidera creare una singola risorsa, in questo modo: inviare un POST a / api / books per creare un libro. Ma poi quando vuoi creare 100 libri (in una singola richiesta come json), su quale URL pubblicheresti la raccolta di 100 libri? è lì che inizia l'irrequietezza.
code4kix

@ code4kix si potrebbe usare /api/book-group, /api/book-collectiono qualcosa di simile.
miguelcobain

46

Sebbene le operazioni in blocco (ad esempio, la creazione in batch) siano essenziali in molti sistemi, non sono formalmente affrontate dallo stile di architettura RESTful.

Ho scoperto che POST di una raccolta come da te suggerito fondamentalmente funziona, ma sorgono problemi quando è necessario segnalare errori in risposta a tale richiesta. Tali problemi sono peggiori quando si verificano più errori per cause diverse o quando il server non supporta le transazioni. Il mio suggerimento è che se non ci sono problemi di prestazioni, ad esempio quando il provider di servizi è sulla LAN (non WAN) o i dati sono relativamente piccoli, vale la pena inviare 100 richieste POST al server. Mantienilo semplice, inizia con richieste separate e se hai un problema di prestazioni prova a ottimizzare.


3
Hai trovato tu stesso una soluzione per gli errori in caso di batch? Su una connessione mobile l'invio di 100 richieste di post per mostrare una pagina sembra una cattiva idea.
Thomas Ahle

Aggiungo gli errori a un array, installo l'utente a una pagina di errore 419 Conflict (e restituisco l'errore al client) e visualizzo l'array di errori. Vedi la mia risposta di seguito per maggiori dettagli.
Eric Fuller

5
Questo non ha senso. La domanda riguarda l'invio di un ordine per molti articoli, che come molti hanno detto, puoi semplicemente fare nell'entità di una richiesta POST. Il modo in cui il server gestisce questa è un'altra cosa. In questo caso, non vedo alcun problema con la creazione di un ordine, la compilazione di ciò che è possibile per quell'ordine e la compilazione di dettagli che non è stato possibile eseguire. In questo modo un utente può quindi vedere il proprio ordine e vedere che tutti gli articoli tranne N sono stati aggiunti all'ordine, ma alcuni erano esauriti o il sistema non sapeva cosa farne. Un'altra opzione più semplice ma meno
intuitiva

2
@thecoshman cambia molto in 3,25 anni. Probabilmente dovresti pubblicare una risposta completamente formulata alla domanda.
dlamblin

3
@dlamblin sì, probabilmente dovrei fare un sacco di cose ... ci
arriverò

9

Facebook spiega come farlo: https://developers.facebook.com/docs/graph-api/making-multiple-requests

Richieste in batch semplici

L'API batch accetta un array di richieste HTTP logiche rappresentate come array JSON: ogni richiesta ha un metodo (corrispondente al metodo HTTP GET / PUT / POST / DELETE ecc.), Un relative_url (la parte dell'URL dopo graph.facebook. com), un array di intestazioni facoltativo (corrispondente alle intestazioni HTTP) e un corpo facoltativo (per richieste POST e PUT). L'API Batch restituisce un array di risposte HTTP logiche rappresentate come array JSON: ogni risposta ha un codice di stato, un array di intestazioni facoltativo e un corpo facoltativo (che è una stringa codificata JSON).


1
Questo è un link molto interessante, la soluzione proposta mi sembra utilizzabile. Ad ogni modo, in StackOverflow la risposta preferita è spiegare il concetto di soluzione nel corpo di una risposta poiché i collegamenti possono cambiare o scomparire.
Jan Vlcinsky

7
Questo è davvero il modo in cui Facebook lo fa, non necessariamente RESTful come ha chiesto l'OP
0cd

Penso che un'API Batch (da Google, Facebook, ecc. - @PuneetArora) sia più utile quando si raggruppano più richieste non correlate. Creare una richiesta che crea un elemento e quindi raggruppare tutte quelle richieste insieme per inviare una raccolta di elementi è "follia" (Einstein). Basta creare una richiesta che passi una raccolta di elementi.
tfmontague

8

La tua idea mi sembra valida. L'implementazione è una questione di tua preferenza. Puoi usare JSON o solo parametri per questo (array "order_lines []") e fallo

POST /orders

Dal momento che creerai più risorse contemporaneamente in una singola azione (ordine e le sue linee) è fondamentale convalidare ognuna di esse e salvarle solo se tutte superano la convalida, ad es. dovresti farlo in una transazione.



5

Ultimamente ho lottato con questo ed ecco a cosa sto lavorando.

Se un POST che aggiunge più risorse ha esito positivo, restituisci 200 OK (stavo considerando un 201, ma l'utente alla fine non atterra su una risorsa che è stata creata) insieme a una pagina che mostra tutte le risorse che sono state aggiunte, sia in lettura -un modo solo o modificabile. Ad esempio, un utente è in grado di selezionare e POSTARE più immagini in una galleria utilizzando un modulo che comprende solo un singolo file di input. Se la richiesta POST riesce nella sua interezza, all'utente viene presentato un insieme di moduli per ciascuna rappresentazione della risorsa immagine creata che gli consente di specificare maggiori dettagli su ciascuna (nome, descrizione, ecc.).

Nel caso in cui non sia possibile creare una o più risorse, il gestore POST interrompe tutta l'elaborazione e aggiunge ogni singolo messaggio di errore a un array. Quindi, viene restituito un 419 Conflict e l'utente viene indirizzato a una pagina di errore 419 Conflict che presenta il contenuto della matrice di errori, nonché un modo per tornare al modulo che è stato inviato.


-2

Non vorrai inviare le intestazioni HTTP per 100 linee d'ordine. Non vuoi nemmeno generare più richieste del necessario.

Invia l'intero ordine in un oggetto JSON al server, a: server / order o server / order / new. Restituisce qualcosa che punta a: server / order / order_id

Considera anche l'utilizzo di CREATE PUT invece di POST


Suppongo che menzioni il metodo HTTP POST. Non esiste un metodo CREATE HTTP.
Milan Novota

Non c'è? Oh aspetta, non c'erano. C'erano invece PUT.
Allegro

22
Perché diavolo useresti PUT per creare contenuti? Questo è esattamente lo scopo del metodo HTTP POST.
thecoshman

8
Si utilizza PUT per creare risorse quando si desidera che il client specifichi l'URI della risorsa, come in webdav. Non sono d'accordo con l'uso di PUT da parte del poster, ma ha un ruolo nella creazione di risorse, sebbene tale spazio possa essere limitato nella portata.
user602525

2
Nota: il POST di un'entità dovrebbe far sì che l'entità diventi una subordinata della risorsa indirizzata nella richiesta e non sia idempotente. PUT sostituisce l'entità all'indirizzo ed è idempotente. L'idempotenza (parola?) È un'aspettativa importante per i consumatori.
Luke Puplett
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.