Cercherò di essere esaustivo riguardo alle possibili soluzioni che potresti utilizzare.
Come hai scritto, ritengo che un prodotto abbia i seguenti attributi: id, nome, disponibilità
1. Progettare una risorsa per ogni attributo
-
/ products / 555 / name :
GET
restituisce il nome corrente dell'id del prodotto 555. PUT newname
modifica il nome corrente dell'ID prodotto 555 con newname
-
/ products / 555 / availability :
GET
restituisce la disponibilità corrente. PUT 99
modifica la disponibilità corrente a 99
.
... e così via ...
Si noti che le risorse non sono "orientate al metodo", corrispondono a un concetto (nome, disponibilità, ecc. di un prodotto) che potrebbe essere aggiornato, recuperato, cancellato, ecc. e non limitato a una particolare funzione.
Si noti inoltre che non sto descrivendo quale sia la chiamata al metodo internamente diversa quando una risorsa riceve una richiesta GET
o PUT
. Questo è totalmente ortogonale. Scriverò una piccola nota al riguardo, alla fine della risposta.
Difetto principale di questo approccio: per aggiornare gli attributi x , un client deve inviare richieste x ... Si vede chiaramente che potrebbe essere noioso per un cliente farlo e consumare anche la larghezza di banda. Ma se va bene, allora vai avanti.
2. Una risorsa con tutti gli attributi
-
/ products / 555 : contiene tutti gli attributi di un prodotto (nome, disponibilità, ecc.). Un
GET
restituisce questi attributi. Per aggiornarli, hai 2 possibilità:
2.1 aggiornamento con PUT
Il metodo PUT ha lo scopo di aggiornare completamente la rappresentazione delle risorse. Significa che il tuo cliente deve inviare tutti gli attributi di un prodotto nel payload.
Immagina che la rappresentazione corrente della risorsa / products / 555 sia:
{ "name": "bread", "availability": 10 }
Se vuoi aggiornare solo la disponibilità a 99
, devi inviare la rappresentazione completa della risorsa, in questo modo:
PUT /products/555 { "name": "bread", "availability": 99 }
Grande svantaggio di questo approccio: un cliente che desidera aggiornare un campo dovrà inviare l'intera rappresentazione della risorsa.
2.2 aggiornamento con PATCH
Il verbo PATCH ha lo scopo di aggiornare parzialmente una rappresentazione della risorsa.
Considerando la rappresentazione corrente del prodotto è { "name": "bread", "availability": 10 }
. Se un cliente desidera aggiornare solo availability
, invierà:
PATCH /products/555 { "availability": 42 }
Fai attenzione, perché PATCH non è idempotente. Significa che questa richiesta:
PATCH /products/555 { "availability": 42 }
può portare ad avere la seguente rappresentazione delle risorse:
{ "name": "bread", "availability": 42 }
o
{ "name": "sugar", "availability": 42 }
Quindi, rompe l'idempotenza ... che PUT
garantisce :)! (poiché con PUT
si invia la rappresentazione completa nel corpo della richiesta)
Potresti anche aggiornare diversi attributi, se la tua risorsa prodotto ce l'ha. Questo è ovviamente meno consumo di banda che la soluzione descritta in 1.
Nota: chiamata metodi di base
Come detto in precedenza, i metodi call sono ortogonali al design delle tue risorse.
Nel tuo caso, hai qualche metodo a grana fine per aggiornare solo un attributo della classe Product ... va bene.
Ma potresti incapsulare questo in un metodo a grana grossa, qualcosa del genere:
Product updateProduct(Product p) {
p.updateName();
p.changeAvailability();
...
return p;
}