REST endpoint per mostrare un'anteprima prima del POST

15

Sto progettando una nuova applicazione web che è supportata da un backend REST e dal frontend HTML + JS.

C'è un metodo POST su di esso per cambiare un'entità (chiamiamo Config), che ha diversi effetti collaterali nello stato di molti elementi dell'applicazione. Supponiamo che POST sia eseguito in questo modo:

POST /api/config BODY {config: ....}

Per questo motivo, vorrei mostrare un'anteprima prima che vengano apportate tali modifiche, affinché l'utente possa notare cosa cambierà.

La cosa che ho pensato prima è di creare un endpoint Get per l'anteprima, inviando il corpo del nuovo stato dell'entità. In questo modo:

GET /api/preview/items BODY {config: ....}

Potrebbe mostrare il nuovo stato per gli articoli con la nuova configurazione.

GET /api/preview/sales BODY {config: ....}

Potrebbe mostrare il nuovo stato per le vendite con la nuova configurazione.

Sembra una buona idea usare il verbo Get perché non sto alterando lo stato dell'applicazione. Tuttavia, l'utilizzo di un corpo di richiesta con richieste GET sembra essere scoraggiato .

C'è qualche buona pratica al riguardo? Un'altra scelta potrebbe essere quella di memorizzare la configurazione come una bozza con un metodo e visualizzare i risultati con altri, ma richiederebbe un ulteriore passaggio e dovendo gestire le bozze nel server:

POST /api/preview/config BODY {config: ....}

GET /api/preview/items?idPreviewConfig=1
    
posta Xtreme Biker 14.07.2017 - 11:43
fonte

6 risposte

26

Questo è troppo specifico del dominio per avere un supporto nativo in HTTP.

Invece, puoi fare una delle seguenti azioni:

  1. Hai una POST /api/config/preview . Sul lato server, l'applicazione saprà che non dovrebbe modificare la configurazione effettiva, ma combinare quella attuale con quella che hai postato e restituire il risultato che indica cosa è stato cambiato.

    Successivamente, se l'utente è soddisfatto del risultato, eseguirà un POST /api/config contenente lo stesso carico utile della richiesta precedente. Ciò sovrascriverà efficacemente la configurazione.

    Il vantaggio di questo approccio è che non stai apportando alcuna modifica alla API corrente. I clienti che non hanno bisogno della funzione di anteprima sarebbero comunque in grado di aggiornare le voci come facevano prima.

    Lo svantaggio è che quando il corpo è grande, significherebbe che sarebbe necessario inviarlo due volte al server. Se questo è il tuo caso, puoi usare il prossimo approccio.

  2. Avere un POST /api/config/prepare che ricorda ciò che è stato inviato in un record temporaneo e restituisce due elementi: l'ID del record temporaneo (ad esempio 12345 ) e l'anteprima delle modifiche.

    Se l'utente è soddisfatto del risultato, eseguirà un POST /api/config/commit/12345 per archiviare definitivamente le modifiche. In caso contrario, la registrazione temporanea può essere conservata per qualche tempo e quindi scartata da un processo cron.

    Il vantaggio è che, anche in questo caso, puoi mantenere intatto l'originale POST /api/config , e i client che non hanno bisogno di un'anteprima non si interromperanno.

    Gli svantaggi sono che (1) gestire la rimozione di record temporanei può essere complicato (cosa ti fa pensare che un'ora sia sufficiente? E se dieci minuti dopo, la memoria non funziona?) Come i client gestiscono un HTTP 404 quando fanno un commit di un record che è scaduto?) e che (2) la presentazione in due passaggi di un record potrebbe essere più complicata di quanto dovrebbe essere.

  3. Sposta la logica di anteprima sul lato client.

risposta data 14.07.2017 - 12:19
fonte
10

Il punto di utilizzo di verbi HTTP specifici per diverse chiamate api in REST è di sfruttare le meccaniche e le aspettative HTTP esistenti.

L'uso di un GET in questo caso sembra andare contro entrambi.

A. Il cliente deve includere un corpo con un GET? inaspettato

B. Il server restituisce una risposta diversa a un get in base al corpo? rompe le specifiche di spec e caching

Se hai difficoltà con le domande RESTful, la mia regola è chiedermelo.

"Com'è meglio di usare il POST per tutto?"

A meno che non vi sia un vantaggio immediato ed evidente, vai con la strategia Just Use POST Stupid (JUPS)

    
risposta data 14.07.2017 - 14:38
fonte
6

Puoi inviare un'intestazione che indica al server "non persistere, mostrami solo quale sarebbe il risultato se lo facessi". Per es.

POST /api/config HTTP/1.1
Host: api.mysite.com
Content-Type: application/json
Persistence-Options: simulate

{
   "config": {
      "key": "value"
   }
}

a cui il server potrebbe rispondere:

HTTP/1.1 200 OK
Persistence-Options: simulated
Content-Type: application/json

-- preview --

Si noti che, se si utilizzano le transazioni O / RM e / o per richiesta di unità di lavoro con il proprio DB, è possibile implementare facilmente questa funzionalità per tutti i punti finali senza richiedere lavoro su alcun particolare endpoint: se una richiesta arriva con questa opzione, ripristina la transazione / unità di lavoro anziché eseguirla.

    
risposta data 14.07.2017 - 12:43
fonte
2

Suggerirei di trattarlo nello stesso modo in cui trattate le ricerche. Vorrei impostare un endpoint POST a /api/config/preview che CREA una nuova anteprima. Quindi imposterei un endpoint PUT o PATCH a api/config a seconda che si intenda modificare la configurazione corrente, o semplicemente sostituire l'intera configurazione (presumibilmente nel primo caso si manderebbe l'anteprima appena creata).

    
risposta data 14.07.2017 - 18:22
fonte
0

Insieme alle altre buone risposte, un'altra opzione potrebbe essere quella di pubblicare la configurazione come accennato, e avere anche un processo di rollback disponibile. Penso che, come la metodologia Agile, sia meglio essere meno spaventati dai cambiamenti avendo procedure più granulari, ripetibili e testate, e questo ti darebbe un backup quando ne hai bisogno, riducendo il rischio a poco o nulla, a seconda dell'applicazione .

Inoltre, se potresti avere errori di configurazione che interessano l'intero sistema, ti piacerebbe gestirlo in modo più attivo, e se questo è il caso, perché non limitarti a visualizzare in anteprima le modifiche a quel punto, da un server o prospettiva del cliente. Anche se, posso vedere come questa funzionalità di anteprima potrebbe essere più costosa da sviluppare, nei casi di utilizzo hanno il loro insieme di passaggi diversi da seguire e testare.

    
risposta data 14.07.2017 - 19:58
fonte
0

RFC6648 deprecano nuovi costrutti X- quindi devo votare contro l'idea di inviare un nuovo campo di intestazione. REST è uno stile di architettura, quello di cui parliamo è RESTful - ma lascia che lo ignori per questo momento.

Poiché REST è rappresentativo (e una simulazione non ha alcuna rappresentazione nella realtà) e Stateful (e una simulazione non è uno stato fino a quando non è impegnata) dobbiamo avere un nuovo ambito, come un ambito di simulazione. Ma dobbiamo chiamarlo emulazione invece di simulazione perché la simulazione include il processo di simulazione ma significa che abbiamo uno stato permanente, una soluzione ideale di una simulazione: un'emulazione. Quindi dobbiamo chiamarlo emulazione nell'URL. Questa potrebbe anche essere una buona soluzione:

GET  /api/emulation - 200 OK {first:1, last:123}
POST /api/emulation/124 - 200 OK
GET  /api/emulation/124/config - 200 OK {config:{tax:8}}
PUT  /api/emulation/124/config {config:{tax:16}} - 200 OK {config:{tax:16}}
GET  /api/emulation/124/items - 200 OK [first:1, last: 3000]
GET  /api/emulation/124/items/1 - 200 OK {price:1.79, name:'Cup'}
--- show emulation ---
--- commit emulation ---
PUT /api/config {config:{tax:16}}
DELETE /api/emulation/124 - 200 OK

C'è un altro approccio .... potresti notare che molte richieste dal client HTML / JavaScript possono produrre Troppe richieste , che raggiunge il limite di circa 17 richieste allo stesso tempo (dai un'occhiata a questa pagina ). È possibile scambiare l'utilizzo di REST e invece di consegnare gli stati oggetto lame è possibile fornire pagine-stato ricche specifiche dell'utente. Esempio:

GET /user/123/config - 200 OK {user:'Tim', date:3298347239847, currentItem:123, 
                  roles:['Admin','Customer'], config:{tax:16}, unsavedChanges:true, ...}

Cordiali saluti

    
risposta data 15.07.2017 - 00:53
fonte

Leggi altre domande sui tag