cerca
Panoramica REST
modifica cronologia stampa login logout

Wiki

UniCrema


Materie per semestre

Materie per anno

Materie per laurea


Help

Panoramica REST

Torna alla pagina di Ingegneria dei Processi Aziendali


  :: Panoramica sul REST :: 

1. Cos'è il REST?

REST è un termine introdotto da Roy Fielding per descrivere uno stile architetturale per applicazioni web, ed è l'acronimo di Representational State Transfer. Per capire cosa significa facciamo un passo indietro.
Il web è formato da risorse, intese come oggetti di interesse. Ad esempio la RAI potrebbe definire come risorsa il programma Blob, ed i client potrebbero accedere alla risorsa attraverso l'URL:
http://www.rai.it/programma/blob
Ciò che viene restituito al client è una rappresentazione della risorsa (ad esempio una pagina html, se è un browser), che lo porrà in un certo stato. Utilizzando i collegamenti ipertestuali inclusi nella rappresentazione ricevuta, il client potrà accedere ad altre risorse (altre rappresentazioni) passando in un nuovo stato. Riassumendo: l'applicazione del client cambia (trasferisce) lo stato ad ogni rappresentazione della risorsa, da cui Representational State Transfer.
Prima di andare avanti, ecco il disclaimer fondamentale: la pagina web NON È una risorsa, ma una sua rappresentazione.


Il REST è un'alternativa leggera ai meccanismi come le RPC e i servizi Web che usano SOAP, WSDL, ecc. Questo non significa che non sia potente, e infatti non c'è nulla che si possa fare in SOAP che non sia possibile realizzare con un'architettura REST.

Va detto infine che il REST non è uno standard, ma ne usa molti: HTTP, URI, formati standard dei file (xml, html, jpg, ...), tipi MIME (text/xml, text/html, image/jpg, ...), ...

2. Principi architetturali

Il REST definisce un insieme di principi architetturali per realizzare i servizi web, che spesso sono dei veri e propri vincoli di progettazione:

  • il modello dell'applicazione è di tipo client-server;
  • il sistema è formato da risorse, che rappresentano sia lo stato che le funzionalità del servizio. Le risorse sono per il REST ciò che i metodi sono per le RPC e per il SOAP;
  • le risorse devono essere identificate tramite URI;
  • deve esistere un' interfaccia uniforme per la comunicazione tra client e server, così che ognuno possa essere sviluppato in modo indipendente;
  • lo stato dell'applicazione deve evolversi attraverso un flusso tra collegamenti ipertestuali;
  • le comunicazioni tra client e server devono essere stateless, ovvero devono contenere tutte le informazioni necessarie per comprendere la richiesta (parametri, contesto, dati), senza contare su altri file salvati sul server. Se questa scelta aumenta da un lato la disponibilità e la scalabilità del sistema, dall'altro si riflette sulle sue prestazioni: troppe richieste e risposte da replicare, dato che il server non può salvarsi un contesto in locale;
  • per alleggerire le problematiche appena citate della comunicazione stateless, il paradigma REST incoraggia l'utilizzo della cache ogni qual volta è possibile. A questo proposito, le risposte dei server dovrebbero essere sempre etichettate come "cacheable" o "non-cacheable" a seconda dei casi, per evitare che i client utilizzino informazioni obsolete per le richieste future;
  • il sistema può essere stratificato aggiungendo dispositivi intermedi (proxy, cache server, gateway, ...) tra i client e le risorse, così da implementare caratteristiche aggiuntive nella rete (sicurezza, Quality of Service, scalabilità, ...).

Non sono invece vincoli di progettazione la piattaforma su cui vengono eseguiti i servizi (non importa se il server è Unix e il client è Mac, o viceversa), né il tipo di linguaggio usato per implementarli.

Nei prossimi sottoparagrafi approfondiremo alcuni dei principi architetturali citati.

2.1 Design delle URL

Linee guida

Ecco alcune linee guida da seguire nella fase di progettazione delle URI:

  • usare nomi (cosa sono) e non verbi (cosa fanno):
    • Cattivo esempio: www.rai.it/scegliprogramma
    • Buon esempio: www.rai.it/programma
  • non utilizzare le URI per passare i parametri attraverso una GET: in un'architettura RESTful le GET dovrebbero usate esclusivamente per operazioni SAFE (vedi paragrafo). Inoltre in questo modo si contribuisce a mantenere le URI più corte e facili da ricordare:
    • Cattivo esempio: www.rai.it/programma/scegli.php?nome=blob
    • Buon esempio: www.rai.it/programma/blob
  • usare solo lettere minuscole;
  • le risorse dovrebbero avere un nome plurale, gli oggetti singolare;
  • scegliere una struttura chiara, intuitiva e facilmente comprensibile:
    • Cattivo esempio: www.rai.it/pg11/pln.php?nm=blob
    • Buon esempio: www.rai.it/programma/blob/orario
  • nascondere la tecnologia implementativa utilizzata, in primo luogo perché all'utente non gliene frega nulla, e in secondo luogo per evitare di fornire indicazioni utili a malintenzionati. Quindi ad esempio niente URL come www.rai.it/servlet/programma, che risparmierebbero molto tempo a potenziali hacker per scoprire come bucarmi il servizio web;
  • alle istanze delle risorse (che hanno vita limitata rispetto al sistema) è comunemente assegnato un identificativo numerico;
  • quando progettiamo la struttura URI dobbiamo tenere conto che l'obiettivo è non cambiarla più. Il REST infatti introduce un accoppiamento molto forte tra client e server (ad esempio incoraggia l'utilizzo di Segnalibri), e spezzarlo è male. Se proprio dobbiamo cambiare una URL, usiamo le redirect;
  • un altro motivo per usare le redirect è per indirizzare risorse con contenuti sensibili, come informazioni personali degli utenti. Ad esempio si potrebbe fare in modo che la richiesta della URL www.banca.it/mio-username/saldo mi ridiriga alla URL col mio username, ad esempio www.banca.it/guido/saldo (possibilmente solo dopo avermi fatto autenticare).

URL logiche e URL fisiche

Una risorsa è un'entità concettuale, e una rappresentazione è la concreta manifestazione della risorsa sull'applicazione del client. Abbiamo detto che ogni risorsa ha un URL associata, ma va chiarito che questa non è una URL fisica, bensì logica.
Per capire meglio consideriamo questa URL di esempio, che restituisce la rappresentazione della risorsa "3230° puntata di Blob":
http://www.rai.it/programma/blob/3230
L'identificativo numerico non deve farci credere che esistono (almeno) 3230 file, uno per ogni rappresentazione della risorsa "puntata di Blob": bastano infatti 2-3 file di script per generare automaticamente il contenuto di tutte le rappresentazioni. Dato però che all'utente va nascosta la tecnologia implementativa dietro ogni URL, gli sarà fornito un indirizzo alla risorsa logica e non a quella fisica che la genera.
Ecco dunque perché le URL di un servizio REST sono chiamate URL logiche, perché non implicano l'esistenza di un file fisico associato.

Breve nota sulle istanze delle risorse: hanno vita limitata rispetto 'identificativo numerico: si tratta di una pratica comune per identificare le istanze delle risorse. Queste

2.2 Interfaccia comune

Avere un'interfaccia comune tra client e server semplifica e disaccoppia l'architettura, facendo sì che le due componenti possano evolvere in modo indipendente. L'interfaccia standard per i servizi web RESTful è il protocollo HTTP, non a caso quello di trasferimento di un ipertesto. Le operazioni supportate sono le cosiddette funzioni CRUD:

  • (CREATE) POST, per creare una sotto-risorsa sul server;
  • (READ) GET, per recuperare lo stato corrente di una risorsa. Va utilizzata solo per operazioni di sola lettura;
  • (UPDATE) PUT, per inizializzare o aggiornare lo stato della risorsa con l'URI data;
  • (DELETE) DELETE, per cancellare una risorsa (dopo la sua esecuzione l'URI che la identifica non sarà più valida).

Per essere più completi, ecco una tabella che mostra gli effetti delle richieste HTTP su due diversi tipi di URI: quelle che identificano gli insiemi di risorse e quelle che le identificano singolarmente.

Risorsa POST GET PUT DELETE
URI insiemi di risorse
www.rai.it/programmi
Crea un nuovo membro dell'insieme (la sua URI è assegnata automaticamente, e di solito viene ritornata al client) Mostra l'elenco delle URI e qualche dettaglio aggiuntivo sui membri dell'insieme Sostituisce l'intero insieme con un altro Cancella l'intero insieme
URI singole risorse
www.rai.it/programmi/blob
Tratta la risorsa indicata come se fosse un insieme e crea una nuova sotto-risorsa al suo interno Restituisce una rappresentazione della risorsa indicata, espressa nel tipo MIME più appropriato Sostituisce la risorsa indicata, e se non esiste la crea Cancella la risorsa indicata dal suo insieme

Codici di risposta

Un altro aspetto importante di una chiamata REST è quella di ritornare il codice di risposta HTTP appropriato. Vediamo i principali:

  • 200 OK: la richiesta ha avuto successo;
  • 201 Created: la richiesta è stata processata e il risultato è la creazione di una nuova risorsa. A questa deve essere assegnato un URL (o più di uno) da ritornare al client chiamante;
  • 204 No Content: il server ha processato la richiesta ma non ha bisogno di ritornare nulla al client;
  • 303 See Other: si tratta di una redirect, e dice che la risposta alla richiesta può essere trovata in un URL diverso da quello contattato ;
  • 400 Bad Request: il server non capisce la richiesta a causa di errori nella sintassi;
  • 401 Unauthorized: la richiesta richiede l'autenticazione dell'utente. La risposta deve avere un campo "WWW-Authenticate" nel suo header, che contenga un challenge applicabile alla risorsa richiesta;
  • 404 Not Found: la risorsa richiesta non è stata trovata;
  • 405 Method Not Allowed: il metodo specificato nella richiesta non è applicabile alla risorsa identificata dall'URL. La risposta deve avere un campo "Allow" nel suo header, che contenga la lista dei metodi validi per quella risorsa;
  • 422 Unprocessable Entity: il server riconosce il formato della richiesta, ma non è in grado di processare le istruzioni in essa contenute.

2.3 Flusso tra ipertesti

Quando si progetta la modalità di navigazione tra ipertesti per i trasferimenti di stato, la regola d'oro è: MAI lasciare al client il compito di costruire la URL per effettuare azioni sulla risorsa, ma INCLUDERLE nella risposta REST sotto forma di elenco di link.

Ad esempio se il client vuole ottenere l'elenco dei programmi della RAI e successivamente accedere alla rappresentazione di uno di questi:

  • Cattiva soluzione: viene dato al client l'elenco dei nomi dei programmi, lasciandogli il compito di costruire l'URL sapendo che lo schema è www.rai.it/programma/[nome_programma];
  • Buona soluzione: viene dato al client l'elenco delle URL dei programmi già creato lato server.

2.4 Stateless o stateful?

Abbiamo detto che le comunicazioni tra client e server devono essere stateless, ma questo non vale per i servizi web o le loro risorse. Come il significato stesso del nome "REST" ci ricorda, tutto ruota intorno al problema di concordare uno stato in un sistema distribuito!
Dal punto di vista dei client lo stato è catturato dalla posizione corrente nell'ipertesto, cioè l'interfaccia attraverso cui possono interagire con le risorse. Il server può influenzare le transizioni di stato del client inviando diverse rappresentazioni nelle risposte alle GET, o inviando diversi collegamenti ipertestuali da seguire.
Dal punto di vista dei server è lo stato della risorsa che cattura lo stato attuale del servizio. In questa prospettiva il client non è solo colui che ha accesso alla risorsa (nelle sue diverse rappresentazioni), ma anche colui che ne può manipolare lo stato usando l'interfaccia CRUD.

Nello schema sotto illustreremo meglio quanto detto finora:

  • il client si trova nello stato "...";
  • il client chiede accesso alla risorsa risorsa, e si sposta nello stato "000";
  • il server gli risponde che accedendo a quella risorsa può passare allo stato "111" o "222";
  • il client sceglie di passare allo stato "111", e il server gli restituisce l'xml relativo.
STATO DEL CLIENT ###                      ### STATO DELLA RISORSA
                 ###                      ###
                  |                        |
       ...        | GET /risorsa           |   ------------------
       ...        |----------------------->|   |/risorsa        |
                  |<-----------------------|   |----------------|
        |         | <a href="1" />         |   |<a href="1" />  |
        |         | <a href="2" />         |   |<a href="1" />  |
                  |                        |   |                |
       000        |                        |   |                |
       000        |                        |   |                |
                  |                        |   |                |
      /   \       | GET /1                 |   |/1              |
     /     \      |----------------------->|   |----------------|
                  |<-----------------------|   |<xml>           |
   111     222    | 200 OK                 |   |                |
   111     222    | <xml>                  |   |----------------|
                  |                        |
                  |                        |

3. Operazioni SAFE e UNSAFE

La funzione POST può essere usata sia in lettura che in scrittura, quindi va trattata con attenzione perché potrebbe cambiare lo stato della risorsa con effetti indesiderati. Ad esempio, se vogliamo incrementare il saldo di un conto corrente di 200€ utilizzando una POST e qualcosa va storto nella comunicazione (ad esempio il server va giù), ripetere l'operazione potrebbe depositare 400€ invece della somma corretta.
Le altre funzioni CRUD sono definite invece idempotenti, perché la loro ripetizione non ha effetti collaterali sulla risorsa:

  • la GET è un'operazione di sola lettura, quindi ripetendola più volte si ottiene una lettura ripetuta della risorsa;
  • la PUT è un'operazione di aggiornamento, quindi ripetendola più volte si otterrà una sovrascrittura dello stato della risorsa sempre con lo stesso valore;
  • la DELETE è un'operazione di eliminazione, quindi se la risorsa è già stata cancellata non avrà alcun effetto, altrimenti la eliminerà.
In particolare, le operazioni idempotenti che non modificano lo stato del server (come la GET) sono definite SAFE; mentre quelle UNSAFE (come la POST) sono l'esatto opposto. Per limitare i potenziali danni di un'esecuzione errata di una UNSAFE è opportuno riformularla sotto forma di una serie di operazioni SAFE. Ad esempio, trasformare l'operazione Deposita(200€); in:
s = GetSaldo() // si usa una GET (operazione SAFE)
s = s + 200€ // operazione eseguita in locale
SetSaldo(s) // si usa una PUT (operazione idempotente)

Si ottiene perciò uno schema di questo tipo:

			 /saldo

OOO                      000
OOO                      000
 |                        |
 |  GET /saldo            |
 |----------------------->|
 |<-----------------------|
 |  200 OK                |
 |  s: 26                 |
 |                        |
 |                        |
 | PUT /saldo             |
 | s: 26                  |
 |----------------------->|
 |<-----------------------|
 |  200 OK                |
 |  s: 27                 |

Il servizio potrebbe essere ulteriormente raffinato, ad esempio tenendo conto delle modifiche concorrenti allo stato della risorsa da parte di due client diversi. Queste potrebbero generare infatti problemi come questo:

			 /saldo

OOO                      000                      888
OOO                      000                      888
 |                        |                        |
 |  GET /saldo            |                        |
 |----------------------->|                        |
 |<-----------------------|  PUT /saldo            |
 |  200 OK                |  s: 26                 |
 |  s: 26                 |<-----------------------|
 |                        |----------------------->|
 |                        |  200 OK                |
 | PUT /saldo             |  s: 27                 |
 | s: 26                  |                        |
 |----------------------->|                        |
 |<-----------------------|                        |
 |  409 Conflict          |                        |

Il messaggio di errore 409 informa che c'è stato un conflitto dovuto all'inconsistenza della risorsa, che era stata infatti chiamata con un valore diverso da quello corrente.

Nei sottoparagrafi seguenti vedremo altri esempi di soluzione dei problemi di utilizzo di operazioni UNSAFE.

3.1 Esempio "Ordini"

Abbiamo creato un servizio web che tra le altre cose permette all'utente di ordinare un oggetto e farselo recapitare a casa. Ciò che vogliamo è che nessun ordine venga perso, e che nessun ordine venga processato due volte (o spediremmo due oggetti uguali). In breve:

  • un singolo ordine deve essere processato una volta sola;
  • in caso di fallimento dell'ordinazione, possiamo tentare ancora.

La soluzione è fare in modo che ogni richiesta d'ordine sia unica. Come? Ad esempio, se stiamo facendo compilare l'ordine attraverso una form html potremo inviare un parametro nascosto (insieme a quelli inseriti dall'utente) che faccia creare lato server un "ticket" dell'ordine. In questo modo se il server riceve una richiesta d'ordine con un ticket già noto potrà facilmente scartarla in quanto duplicato. Vediamo lo schema:

CLIENT			        SERVER

 OOO                             000
 OOO                             000
  |                               |
  |  POST                         |
  |------------------------------>| (insieme "ticket")
  |<------------------------------|
  |  200 OK                       |
  |  ticket                       |
  |                               |
  |                               |
  | POST                          |
  | ordine+ticket                 |
  |------------------------------>| (insieme "ordini aperti")
  |<------------------------------|
  |  201 Created                  |
  |  Location: URI ordini aperti  |

Alcune caratteristiche che deve avere il ticket:

  • deve essere unico (ad esempio GUID, UUID, ...);
  • non deve essere salvato sul server (o basterebbero una decina di client scritti male perché la loro connessione continui a fallire e siano richiesti milioni di ticket);
  • deve essere robusto;
  • i ticket usati con successo devono essere archiviati e associati agli ordini creati.

3.2 Esempio "Ordini 2"

Proviamo a trovare una soluzione alternativa a quella descritta nel paragrafo precedente.
Se prima abbiamo "incorporato" il ticket nei dati inviati tra client e server, ora lo utilizzeremo per creare un ordine pendente, cioè una URL su cui il client potrà ordinare usando una PUT. Una volta ordinato con successo, l'ordine pendente sarà spostato nell'insieme di risorse ordini aperti, a cui il client sarà rediretto con una risposta dal server con codice di stato 303 ("la risposta alla richiesta può essere trovata sotto un'altra URI usando il metodo GET").
Ecco lo schema:

CLIENT			          SERVER

 OOO                               000
 OOO                               000
  |                                 |
  |  POST                           |
  |-------------------------------->| (insieme "ordini pendenti")
  |<--------------------------------|
  |  201 Created                    |
  |  Location: URI ordine pendente  |
  |                                 |
  |                                 |
  | PUT                             |
  | ordine                          |
  |-------------------------------->| (ordine pendente)
  |<--------------------------------|
  |  303 See Other                  |
  |  Location: URI ordine aperto    |

Si tratta di una soluzione migliore della precedente, perché usa l'operazione PUT che è meravigliosamente idempotente: potremo quindi continuare a inoltrare la richiesta finché questa non avrà successo.
L'insieme "ordini pendenti" non sarà altro che una nuova risorsa, che avrà dunque bisogno di essere considerata nella fase di design delle URI.

4. Metodologia di progettazione

Una possibile metodologia di progettazione di un servizio REST è la seguente:

  1. identificare le risorse da mostrare come servizi (ad esempio "elenco programmi", "report annuali di rischio", "catalogo libri", "tratte aeree", "sondaggi", ...);
  2. modellare le relazioni (ad esempio "è contenuta", "referenzia", "è una transizione di stato", ...) tra risorse tramite collegamenti ipertestuali. In questa fase bisogna evitare di creare delle "isole", ovvero rappresentazioni scollegate o irraggiungibili dalle altre;
  3. definire URI appropriate per indirizzare le risorse;
  4. decidere cosa far fare alle risorse attraverso le funzioni messe a disposizione dall'interfaccia comune. Si tenga conto che le informazioni andrebbero rivelate gradualmente: meglio avere tanti link per ottenere maggiori informazioni che inviare un singolo mega-documento di risposta;
  5. progettare e documentare la rappresentazione..
    • ..del formato delle richieste e delle risposte, utilizzando uno schema come il DTD, il W3C schema, ...;
    • ..del servizio, utilizzando un documento WSDL o un semplice html.
  6. implementare e fare il deploy del web server;
  7. testarlo con un browser.

5. Esempio finale: SONDAGGIO

Progettiamo l'applicazione web "POTA, VOTA!" che permette di creare sondaggi e di votare, e proviamo a seguire i primi quattro passi della metodologia di progettazione descritti sopra.

5.1 Identificare le risorse

Le risorse individuate sono:

  • poll, che identifica l'insieme dei sondaggi;
  • vote, che identifica l'insieme dei voti.

5.2 Relazioni tra le risorse

Ogni sondaggio dell'insieme poll è identificato da un {id}, così come le istanze dell'insieme vote. L'{id} potrebbe essere benissimo un identificativo numerico.
Ogni istanza di sondaggio contiene la sotto-risorsa voto, che a sua volta contiene i voti effettivi degli utenti. Graficamente potremo avere una struttura di questo tipo:

poll
   {id1}
      vote
         {id4}
         {id5}
   {id2}
   {id3}
   ...

La strategia con cui vengono assegnati gli {id} dipende dalla funzione CRUD utilizzata per istanziare le risorse. La questione sarà approfondita nei paragrafi successivi.

5.3 Definire le URI

Le URI delle risorse dovranno incorporare gli {id} delle loro istanze, quindi avremo qualcosa come:

  • www.potavota.it/poll/01234, si riferisce al sondaggio 01234;
  • www.potavota.it/poll/01234/vote/2, si riferisce al voto 2 del sondaggio 01234.

5.4 Definire l'interfaccia comune

5.4.1 Creare un sondaggio

Per creare un sondaggio dovremo:

  1. creare un documento xml conforme allo schema che "POTA, VOTA!" ha progettato per i sondaggi (e che ad esempio ha reso noto in un documento WSDL);
  2. inviare il documento al web server usando una POST.
	  	                     /poll
			             /poll/01234

888 -------------------------------> 000
888 <------------------------------- 000

  POST /poll
  Host: www.potavota.it
  Content-Type: application/xml
  <?xml version="1.0">		
  <options>A,B,C</options>	

  201 Created		
  Location: /poll/01234

Il server assegna al sondaggio appena creato una URL (www.potavota.it/poll/01234), che in futuro può essere usata come servizio web anche da altri client.
Ripetiamo per l'ennesima volta che il modo in cui il web service genera il sondaggio è completamente trasparente al client: l'unica cosa che deve sapere è che se invia quell'xml con una POST otterrà la creazione di una nuova istanza della risorsa poll. In virtù di questa trasparenza, i programmatori del servizio sono liberi di modificare l'implementazione delle risorse senza che il client ne risenta.

5.4.2 Leggere voti o sondaggi

Per leggere il contenuto di un messaggio o di un voto useremo una GET.

/poll
/poll/01234
/poll/01234/vote

000 <------------------------------- 888
000 -------------------------------> 888

  GET /poll/01234 HTTP/1.1
  Host: www.potavota.it
  Accept: application/xml

  200 OK
  <options>A,B,C</options>
  <votes href="/vote">

Il formato del documento che il server deve restituire a una GET non deve essere specificato nell'URI, ma nell'header della GET come valore del parametro Accept:, in cui va inserita la lista di tipi MIME accettati dal client.
Forzare il formato del documento da ricevere nell'URI (ad esempio con una GET www.potavota.it/poll/01234.html) non è un'ottima strategia per il client, perché il server potrebbe non essere in grado di rappresentare la risorsa nel formato richiesto e non gli ritornerebbe niente.

5.4.3 Votare

Partecipare al sondaggio significa creare una sotto-risorsa di tipo voto all'interno del poll interessato. Nello schema seguente (come nei successivi) sarà mostrata a sinistra l'operazione e a destra la verifica del suo risultato utilizzando una GET:

			              /poll
			              /poll/01234
		  	              /poll/01234/vote
			              /poll/01234/vote/1

888 --------------------------------> 000 <------------------------------ 888
888 <-------------------------------- 000 ------------------------------> 888

  POST /poll/01234/vote		            GET /poll/01234
  Host: www.potavota.it                     Host: www.potavota.it
  Content-Type: application/xml             Accept: application/xml
  <?xml version="1.0">	
  <name>Pippo</name>		            200 OK
  <choice>B</choice>                        <options>A,B,C</options>
                                            <votes>
  201 Created			              <vote id="1">
  Location:			                <name>Pippo</name>
  /poll/01234/vote/1		                <choice>B</choice>
				     	      </vote>
				            </votes>

5.4.4 Cambiare il voto

Cambiare il voto in un sondaggio significa aggiornare il valore di quello già dato, per cui dovremo utilizzare la chiamata PUT:

			              /poll
			              /poll/01234
		  	              /poll/01234/vote
			              /poll/01234/vote/1

888 --------------------------------> 000 <------------------------------ 888
888 <-------------------------------- 000 ------------------------------> 888

  PUT /poll/01234/vote/1 HTTP/1.1           GET /poll/01234
  Host: www.potavota.it                     Host: www.potavota.it
  Content-Type: application/xml             Accept: application/xml
  <?xml version="1.0">
  <name>Pippo</name>		            200 OK
  <choice>C</choice>                        <options>A,B,C</options>
                                            <votes>
  200 OK			     	      <vote id="1">
				                <name>Pippo</name>
				                <choice>C</choice>
					      </vote>
				            </votes>

Ora che abbiamo visto sia la POST che la PUT possiamo chiederci: "qual è il metodo corretto per creare una risorsa inizializzando il suo stato??"
La risposta è: dipende. Da cosa? Dal modo in cui vogliamo che gli {id} siano generati:

  • Con la PUT l'inizializzazione dell'istanza avviene insieme alla richiesta:
    -> PUT /resource/{id} 
    <- 201 Created
    Il sistema è a prova di fallimenti (la PUT è idempotente), ma dovremo assicurare che l'{id} sia univoco (due client concorrenti potrebbero creare due risorse diverse assegnandogli lo stesso identificativo). La soluzione potrebbe essere l'utilizzo di una GUID;
  • Con la POST lasciamo al server l'onere di creare un {id} univoco:
    -> POST /resource 
    <- 301 Moved Permanently 
       Location: /resouce/{id}
    Il problema di questa soluzione è complementare a quello precedente: la POST è UNSAFE, quindi ripeterla due volte in caso di fallimento della comunicazione potrebbe avere effetti indesiderati.

In realtà c'è una terza via: predisporre una URL del tipo www.potavota.it/poll/poll-new da richiamare con una GET, che restituirà al client tutte le informazioni necessarie per creare una nuova risorsa con una POST. Queste informazioni potrebbero essere sotto forma di form html, o di prototipo xml, o di altro tipo.

5.4.5 Cancellare voti o sondaggi

Infine, per cancellare un voto già dato o un intero sondaggio si userà la richiesta DELETE. Nell'esempio che segue mostreremo come avviene la cancellazione del sondaggio con ID 01234 (si noti che la GET successiva restituisce l'avviso che la risorsa non è stata trovata):

			      /poll
			      /poll/01234
		 	      /poll/01234/vote
			      /poll/01234/vote/1

888 ------------------------> 000 <------------------------ 888
888 <------------------------ 000 ------------------------> 888

DELETE /poll/01234		     GET /poll/01234
                                     Host: www.potavota.it
200 OK				     Accept: application/xml

                                     404 Not Found

6. Breve considerazione sui cookie

In un'architettura REST ben progettata i cookie non dovrebbero essere né presenti, né tanto meno necessari. In primo luogo per una coerenza di design: le chiamate devono essere stateless, quindi dovrebbero contenere al loro interno tutte le informazioni necessarie perché il server le processi. Poiché i cookie per definizione sono informazioni esterne alle chiamate, rappresenterebbero un'eccezione allo stile architetturale.
Il secondo motivo riguarda invece la scalabilità del sistema. Supponiamo ad esempio che i cookie contengano anche solo una chiave di sessione che catturi lo stato dell'applicazione. In questo caso il client dovrà trasferire meno informazioni per chiamata, ma il server sarà obbligato a salvarsi da qualche parte i dati contenuti nel cookie: più sono i client e più saranno i dati da salvare. Inoltre il server si dovrà dotare di un qualche meccanismo di garbage collection per ripulire tutte le sessioni diventate ormai inattive, e all'aumentare dei client serviti il carico di lavoro diventerebbe sempre più oneroso.


Torna alla pagina di Ingegneria dei Processi Aziendali