Operazioni non CRUD in un servizio RESTful


106

Qual è il modo "RESTful" di aggiungere operazioni non CRUD a un servizio RESTful? Supponiamo che io disponga di un servizio che consente l'accesso CRUD a record come questo:

GET /api/car/123           <- Returns information for the Car object with ID 123
POST /api/car              <- Creates a new car (with properties in the request)
PUT /api/car/123           <- Updates car 123 (with properties in the request)
DELETE /api/car/123        <- Deletes car 123    
POST /api/car/123/wheel/   <- Creates a wheel and associates it to car 123

Se voglio cambiare il colore dell'auto, POST /api/car/123includerei semplicemente una variabile POST per il nuovo colore.

Ma supponiamo che io voglia acquistare un'auto e che l'operazione sia più complicata del semplice aggiornamento della proprietà di "macchina di proprietà" di un record "utente". È RESTful fare semplicemente qualcosa come POST /api/car/123/purchase, dove "acquisto" è essenzialmente un nome di metodo? O dovrei usare un verbo HTTP personalizzato, come PURCHASEinvece di POST?

O le operazioni non CRUD sono completamente al di fuori dell'ambito di REST?


5
Se stai cambiando il colore di un'auto, sarebbe meglio usare PATCH /api/car/123e inviare un parametro di colore OPPURE usare PUT /api/car/123e inviare l'intero oggetto auto. POST dedurrebbe che stai creando una nuova auto e probabilmente non dovresti mai includere un ID alla fine dell'URL
RonnyKnoxville,

Risposte:


65

Pensa all'acquisto come a un'entità aziendale o a una risorsa nel dizionario RESTful. Detto questo, effettuare un acquisto significa creare una nuova risorsa. Così:

POST /api/purchase

effettuerà un nuovo ordine. I dettagli (utente, auto, ecc.) Devono essere referenziati tramite id (o URI) all'interno dei contenuti inviati a questo indirizzo.

Non importa che ordinare un'auto non sia solo un semplice INSERIMENTO nel database. In realtà, REST non riguarda l'esposizione delle tabelle del database come operazioni CRUD. Dal punto di vista logico stai creando un ordine (acquisto), ma il lato server è libero di eseguire tutte le fasi di elaborazione che desidera.

Puoi persino abusare ulteriormente del protocollo HTTP. Usa l' Locationintestazione per restituire un collegamento all'ordine appena creato, scegli attentamente i codici di risposta HTTP per informare gli utenti sui problemi (lato server o lato client), ecc.


3
REST è incentrato sulla manipolazione dello stato delle risorse e ogni operazione aziendale deve essere mappata alle operazioni CRUD di stato. Se hai bisogno di una semantica delle operazioni aziendali complesse, dovrai seguire la via SOAP (SOAP è in realtà il passaggio di messaggi, ma è tipicamente organizzato in operazioni di richiesta-risposta).
Tomasz Nurkiewicz

23
Il design "acquista come risorsa" sembra pulito. E se la risorsa fosse una "birra" .. e voglio che il cameriere la beva .. (se fosse per me, la prenderei sicuramente;)) .. dovremmo considerare la "bevanda azione" come una risorsa ?! .. o è "bere una birra", un affare duro ?! Più seriamente, il progetto RESTful consiste nel considerare le azioni come risorse?! ..
Myobis

2
Come esporresti l '"approvazione dell'ordine di acquisto" tramite un servizio REST? Penso che @TomaszNurkiewicz abbia ragione in quanto tutto ciò che non può essere fatto in modo ordinato in modo CRUD avrà bisogno della semantica operativa fornita da SOAP. A meno che "l'approvazione dell'ordine di acquisto" non sia un modello / entità a sé stante. Ad esempio, approvazione POST / po (con dettagli PO nella richiesta).
mydoghasworms

2
Dal punto di vista di un cliente REST, "approva l'ordine di acquisto" dovrebbe essere solo un altro aggiornamento dell'ordine. Ad esempio, modificare "Approvato" in "vero" e inviare l'aggiornamento al server. Il server probabilmente avrà bisogno di fare un mucchio di controlli e probabilmente dovrà aggiornare / creare un mucchio di altre risorse. Ma questo è il problema dei server e non dovrebbe essere visibile al client.
AVee

2
@antinome: "Supponiamo che il client sappia qualcosa di questo", se questo è il caso che non stai facendo REST (potrebbe comunque essere un software valido e ragionevole!). REST è stato progettato per poter creare client che non conoscono quel genere di cose, per creare client che funzionano ancora se il comportamento del server cambia. Quello che stai cercando di fare è il classico RPC, devi rivedere il tuo approccio in modo che si adatti a REST, o accettare che stai facendo RPC e usi un protocollo destinato a RPC come SOAP. REST si sforza molto di non essere RPC, quindi non sarà mai adatto quando si desidera / è necessario RPC.
AVee

15

Il modo RESTful da quanto ho capito è che non hai bisogno di nuovi verbi HTTP, c'è un nome da qualche parte che significherà quello che devi fare.

Acquistare una macchina? Beh, non è quello

POST /api/order

2
PUT non viene utilizzato per aggiornare le risorse poiché è idempotente? Ciò significa che puoi chiamarlo tutte le volte che vuoi, ma solo la prima / ultima chiamata è importante. POST d'altra parte viene utilizzato per creare risorse e chiamarlo due volte dovrebbe effettivamente crearne due.
Tomasz Nurkiewicz

1
@Tomas, sì, errore di battitura. Il principio è importante però, abbiamo a che fare con una cosa nuova, un ordine, non c'è bisogno di un nuovo verbo.
djna

5

Quello che stai davvero facendo è creare un ordine. Quindi aggiungi un'altra risorsa per l'ordine e la pubblicazione e inseriscila durante il processo di ordine.

Pensa in termini di risorse piuttosto che di chiamate ai metodi.

Per finalizzare l'ordine che probabilmente avresti POST / api / order // completato o qualcosa di simile.


3

Ritengo che le API REST siano d'aiuto in molti più modi rispetto alla semplice fornitura di semantica. Quindi non è possibile scegliere lo stile RPC solo a causa di alcune chiamate che sembrano avere più senso nello stile operativo RPC. L'esempio è l'API di Google Maps per trovare indicazioni tra due luoghi. Assomiglia a questo: http://maps.googleapis.com/maps/api/directions/json?origin=Jakkur&destination=Hebbal

Avrebbero potuto chiamarlo "findDirections" (verbo) e trattarlo come un'operazione. Piuttosto hanno fatto "direzione" (sostantivo) come una risorsa e hanno trattato la ricerca di direzioni come una query sulla risorsa delle indicazioni stradali (sebbene internamente non possa esserci alcuna risorsa reale chiamata direzione e potrebbe essere implementata dalla logica aziendale per trovare le direzioni in base ai parametri).


Questo è un cattivo esempio. In questo caso le direzioni (tutte le direzioni possibili, un numero infinito di esse) sono la risorsa ei parametri sono solo filtri. Ma non puoi fare un "acquisto" con questo, poiché i filtri hanno senso solo per le operazioni di ricezione e l'inserimento di un ordine o l'annullamento sono operazioni che modificano i dati
Tseng

2
l'acquisto sarebbe POST to / order con un json nel corpo per indicare che è stato creato un ordine. annullare sarebbe PUT to / order con un json che trasporta la modifica dello stato dell'ordine per indicare che si tratta di un aggiornamento idempotente. Devo ancora incappare in un'operazione che non può essere espressa in un formato risorsa. Quindi mi piacerebbe vedere un esempio come questo
Maruthi
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.