2009-09-15 10 views
19

Ho una risorsa con un contatore. Per motivi di esempio, che chiameremo la risorsa profilo, e il contatore è il numero di vista per quel profilo.Incremento del contatore di risorse in modo RESTful: PUT vs POST

Per REST wiki, le richieste PUT devono essere utilizzate per la creazione o la modifica di risorse e devono essere idempotenti. Questa combinazione va bene se aggiorno, ad esempio, il nome del profilo, perché posso rilasciare una richiesta PUT che imposta il nome su qualcosa 1000 volte e il risultato non cambia.

Per queste richieste PUT standard, devo browser fare qualcosa di simile:

PUT /profiles/123?property=value&property2=value2 

Per incrementare un contatore, si chiama l'url in questo modo:

PUT /profiles/123/?counter=views 

Ogni chiamata comporterà il contatore essere incrementato. Tecnicamente si tratta di un'operazione di aggiornamento, ma viola idempotenza.

Sto cercando una guida/best practice. Stai facendo questo come un POST?

risposta

8

Un'alternativa potrebbe essere quella di aggiungere un'altra risorsa al sistema per tracciare le visualizzazioni di un profilo. Potresti chiamarlo "Visualizzazione".

Per vedere tutte le visualizzazioni di un profilo:

GET/profiles/123/visioni

Per aggiungere una visualizzazione a un profilo:

POST/profiles/123/visioni #qui, è 'd inviare i dettagli utilizzando un tipo di supporto personalizzato nel corpo della richiesta.

Per aggiornare un Viewing esistente:

PUT/attributi visioni/815 # submit riveduta della visualizzazione nel corpo della richiesta utilizzando il tipo di supporto personalizzato creato.

il drill-down nei dettagli di una visione:

GET/visioni/815

Per eliminare una visione:

cancellare/visioni/815

Inoltre, perché si' chiedendo le migliori pratiche, assicurati che il tuo sistema RESTful sia hypertext-driven.

Per la maggior parte, non c'è niente di sbagliato nell'usare i parametri di query negli URI - semplicemente non dare ai clienti l'idea di poterli manipolare.

Invece, creare un tipo di supporto che racchiuda i concetti che i parametri stanno cercando di modellare. Assegna a questo tipo di supporto un nome conciso, non ambiguo e descrittivo. Quindi documenta questo tipo di supporto. Il vero problema di esporre i parametri di query in REST è che la pratica spesso conduce comunicazioni out-of-band, e quindi aumenta l'accoppiamento tra client e server.

Quindi fornire al sistema un'interfaccia uniforme. Ad esempio, l'aggiunta di una nuova risorsa è sempre un POST. L'aggiornamento di una risorsa è sempre un PUT. L'eliminazione è DELETE e getiing è GET.

La parte più difficile di REST è la comprensione di come i tipi di media sono presenti nella progettazione del sistema (è anche la parte che Fielding ha lasciato fuori dalla sua tesi perché ha esaurito il tempo). Se si desidera un esempio specifico di un sistema basato su ipertesto che utilizza i tipi di supporti doucuments, vedere Sun Cloud API.

+0

Giusto per chiarire:/le visualizzazioni/815 si riferisce alla visualizzazione 815 di un profilo, sì? –

9

Penso che la risposta corretta sia usare PATCH. Non ho visto nessun altro raccomandarlo dovrebbe essere utilizzato per incrementare un contatore atomicamente, ma credo RFC 2068 dice tutto molto bene:

Il metodo PATCH è simile a PUT, tranne che l'entità contiene un elenco di differenze tra la versione originale della risorsa identificata dall'URI della richiesta e il contenuto desiderato della risorsa dopo l'applicazione dell'azione PATCH. L'elenco delle differenze è in un formato definito dal tipo di media dell'entità (ad esempio, "application/diff") e DEVE includere informazioni sufficienti per consentire a il server di ricreare le modifiche necessarie per convertire la versione originale del risorsa per la versione desiderata.

Così, per aggiornare il numero di visualizzazioni del profilo 123 di, lo farei:

PATCH /profiles/123 HTTP/1.1 
Host: www.example.com 
Content-Type: application/x-counters 

views + 1 

Se il tipo x-counters supporto (che ho appena inventato) è fatto di linee multiple di field operator scalar tuple. views = 500 o views - 1 o views + 3 sono tutti sintatticamente validi (ma possono essere vietati semanticamente).

Riesco a capire un po 'di accigliamento su un altro tipo di supporto, ma suggerisco umilmente che è più corretto rispetto all'alternativa POST/PUT. Creare una risorsa per un campo, completo del suo URI e soprattutto dei suoi dettagli (che non tengo davvero, tutto ciò che ho è un intero) suona sbagliato e ingombrante per me. Cosa succede se ho 23 contatori diversi da mantenere?

+1

Si discosta dallo standard un po 'perché non ha "il contenuto desiderato della risorsa dopo l'applicazione dell'azione PATCH". Per esempio. l'entità è un'istruzione da eseguire, non il risultato desiderato. – Pocketsand

+0

In seguito a ciò che @Pocketsand ha detto, questo approccio non viola il vincolo di "Manipolazione delle risorse attraverso le rappresentazioni" sotto il vincolo "Uniform Interface"? Dove dovresti inviare una rappresentazione della risorsa che vuoi vedere, invece di inviare istruzioni su come manipolarla. – dayuloli

+0

@dayuloli Se stai ancora pensando a una soluzione, ho [aggiunto una risposta] (https://stackoverflow.com/questions/1426845/incrementing-resource-counter-in-a-restful-way-put-vs-post/44852115 # 44852115) con quello che ho deciso di adottare, potrebbe essere adatto alle vostre esigenze. – Pocketsand

0

Penso che entrambi gli approcci di Yanic e Rich siano interrelati. Un PATCH non ha bisogno di essere sicuro o indipente, ma può essere al fine di essere più robusto contro la concorrenza. La soluzione di Rich è certamente più facile da usare in un'API REST "standard".

Vedi RFC5789:

PATCH non è né sicuro né idempotente come definito da [RFC2616], Sezione 9.1.

Una richiesta patch può essere rilasciato in modo tale da essere idempotente, che aiuta anche a prevenire esiti negativi da collisioni tra due richieste cerotto sulla stessa risorsa in un lasso di tempo simile. Le collisioni da più richieste PATCH possono essere più pericolose delle collisioni PUT perché alcuni formati di patch devono operare da un punto base noto altrimenti corromperanno la risorsa.

0

Dopo aver valutato le risposte precedenti ho deciso PATCH era inadeguato e, per i miei scopi, trafficando con Content-Type per un compito banale è stata una violazione della KISS principle. Ho solo bisogno di incrementare n + 1 così ho fatto questo:

PUT /profiles/123$views 
++ 

Dove ++ è il corpo del messaggio e viene interpretato dal controller come istruzione per incrementare la risorsa per uno.

ho scelto $ a delimitare il campo/proprietà della risorsa in quanto è un legal sub-delimiter e, per i miei scopi, sembrava più intuitivo di / che, a mio parere, ha l'atmosfera di traversability.