REST, quanto costa l’infedeltà?

REST, quanto costa l’infedeltà?

In questo ultimo post sul modello REST voglio provare a rispondere ad una semplice domanda: perché dovremmo rimanere fedeli al modello REST quando realizziamo applicazioni web?

Per farlo dobbiamo partire dagli obiettivi che questa architettura si pone:

  1. scalabilità geografica;
  2. adozione di interfacce generiche (es.: HTTP, URI, ecc.) condivise tra tutti i client e server;
  3. deploy indipendente dei componenti (es.: siti web, web app, browser, motori di ricerca, ecc.);
  4. adozione di middleware per ridurre la latenza delle interazioni (es.: proxy web con funzionalità di cache).

Avrete certamente riconosciuto temi importanti che si incrociano quotidianamente nello sviluppo di applicazioni web, d’altronde il Web non è altro che l’implementazione del modello REST su scala mondiale. Eppure nello sviluppo web non sempre si adottano soluzioni in linea con questa architettura.

Realizzare applicazioni web senza rispettare il modello REST non è necessariamente un errore ma generalmente porta a risultati che non beneficiano delle caratteristiche precedentemente elencate. Provo quindi a fare qualche esempio di mancato rispetto del modello REST nelle applicazioni web, per analizzarne di volta in volta le conseguenze. Per individuare questi casi basta cercare i contesti in cui vengono utilizzati, ma non rispettati, gli standard HTTP e URI* che sono alla base dell’adozione del modello REST nel Web.

Single-page application

Le single-page application sono quelle applicazioni web che espongono tutte le loro funzionalità su di un singolo URI. Queste applicazioni non rispettano il principio REST secondo cui ad un identificativo deve essere associata una specifica risorsa, pertanto non rispettano una dell’interfacce generiche del Web, gli URI. Ne consegue che i client di queste applicazioni, come i browser, i motori di ricerca e i sistemi di analisi del traffico, non funzioneranno correttamente. Infatti:

  • La cronologia del browser rimane ferma all’unico URL utilizzato dall’applicazione e di conseguenza le frecce “avanti” e “indietro” del browser non funzionano come dovrebbero. Per la stessa ragione anche i “preferiti” del browser sono piuttosto inefficaci. È necessario adottare specifiche strategie (Fragment identifier o History API) per aggirare il problema.
  • I motori di ricerca non riescono a navigare all’interno dell’applicazione e ad indicizzare le diverse risorse poiché queste vengono servite dallo stesso URL.
  • I servizi di analisi del traffico web hanno difficoltà a distinguere le visite effettuate alle diverse sezioni dell’applicazione.

Submit ripetuto dei form

Vi è mai capitato di utilizzare la freccia “indietro” del browser ed imbattervi in quell’avviso che vi chiede conferma sull’invio del form? Ciò succede quando l’applicazione web non rispetta il significato dei verbi, o metodi, dell’HTTP.

Secondo le specifiche di questo protocollo, il metodo GET deve essere utilizzato esclusivamente per recuperare una risorsa dal server, quindi soltanto nei link delle pagine HTML e nei form di ricerca. Il metodo POST invece deve essere utilizzato per richiedere al server di accettare l’entità (i dati) presenti nella request come subordinati rispetto a quelli associati all’URL. In risposta il server dovrebbe limitarsi ad indicare l’esito della richiesta, ad esempio 201 Created, ed un URL su cui proseguire la navigazione mediante una nuova richiesta GET.

Spesso invece le applicazioni web rispondono ad una richiesta POST con una pagina HTML. Il browser la aggiunge alla sua history, associandola alla request necessaria al suo ottenimento. Queste request dovrebbero essere tutte di tipo GET, quindi ripetibili senza ripercussioni per il server, ma l’applicazione web non sta rispettando il protocollo. Alla pressione del tasto “indietro”, il browser ci chiede conferma prima di ripetere il POST, poiché questo tipo di richiesta potrebbe modificare lo stato del server. Il mancato rispetto del protocollo HTTP può esporre quindi la nostra applicazione ad indesiderate ed involontarie modifiche ai dati, semplicemente navigando la history del browser.

L’approccio più corretto che una web app dovrebbe seguire va sotto il nome di pattern PRG (Post, Redirect, Get) secondo cui il server, a fronte di una richiesta di tipo POST, deve rispondere con un redirect all’URL contenente la successiva risorsa da restituire al browser. Questa verrà recuperata con una ulteriore request, questa volta di tipo GET.

POST nei form di ricerca

I form HTML impiegati per la ricerca all’interno di archivi dovrebbero sempre utilizzare il metodo GET. Infatti questi form servono a recuperare risorse dal server (GET), non a modificare lo stato del server (POST). A volte invece questi form utilizzano erroneamente delle request di tipo POST a cui il server risponde direttamente con la pagina web contenente i risultati. Oltre ai problemi di submit ripetuto precedentemente descritti, questo errore impedisce ai sistemi di cache (browser, proxy cache) di funzionare poiché lo standard prevede che la response di un POST non venga memorizzata in cache. Inoltre le pagine dei risultati non saranno indicizzabili dai motori di ricerca poiché, come le single page application, su di un unico URL vengono mostrati risultati di ricerche aventi diversi criteri.

Servizi SOAP

I servizi SOAP su HTTP sono un caso eclatante di utilizzo “abusivo” degli URI e dell’HTTP, anzi sono in contrapposizione con il modello REST. Infatti su di un unico URL vengono esposte diverse risorse e funzionalità. Inoltre l’HTTP viene utilizzato solamente come “lascia passare” verso i vari apparati di sicurezza delle reti, generalmente configurati per consentire le trasmissioni effettuate con questo protocollo. I messaggi XML dei servizi SOAP contengono tutte le informazioni necessarie all’interazione client-server. Non serve quindi utilizzare l’URI come sistema di identificazione delle risorse, né l’HTTP per specificare cosa chiede il client e l’esito di tale richiesta.

Banalizzando potremmo dire che l’interfaccia di un qualsiasi sito o applicazione web è identica: URI e HTTP. Ed infatti un qualunque client, come un browser, è in grado di interagire correttamente con qualsiasi sito o applicazione web. Invece l’interfaccia dei servizi SOAP è sempre diversa e non è possibile realizzare un client che funzioni con tutti i servizi SOAP. Lo sviluppo di un client SOAP non può prescindere dalla conoscenza dell’interfaccia del particolare servizio SOAP con cui dovrà interagire. Anzi, molto spesso si realizza un servizio SOAP conoscendo già il sistema che dovrà invocarlo.

Ne consegue che i tradizionali sistemi di navigazione ed indicizzazione del Web non funzionano coi i servizi SOAP che invece ricorrono a specifiche soluzioni, come i WSDL e i registri UDDI. Inoltre in SOAP l’utilizzo di interfacce specifiche impedisce anche l’impiego di tradizionali sistemi intermediari, come proxy web con funzione di cache o di controllo degli accessi, poiché questi non saprebbero come interpretare i messaggi SOAP. Anche in questo caso ci si affida a specifiche soluzioni come, ad esempio, gli ESB.

I servizi RESTful su HTTP si affidano invece a questo protocollo e agli URI per adottare una interfaccia standard tra client e server. Di conseguenza si prestano meglio all’utilizzo “world wide”, sotto forma di API a disposizione di un generico sistema client, non noto al server. Se ben realizzato, per navigare all’interno delle risorse esposte da un servizio RESTful è sufficiente conoscere l’URL principale dal quale si dovrebbero ricevere informazioni sulle altre risorse (URL) disponibili, un po’ come accade con la home page di un sito web che permette di accedere, mediante link, a tutte le ulteriori pagine del sito.

I servizi RESTful quindi non sono né migliori né peggiori dei servizi SOAP. I primi fanno uso di interfacce standard orientate alle risorse, i secondi invece utilizzano interfacce specifiche, orientate per lo più all’esecuzione di procedure remote (RPC), di derivazione RMI e CORBA.

Conclusioni

Dopo questa lunga dissertazione provo a condensare il tutto con tre concetti che, a mio avviso, dovrebbero essere ben chiari a ciascuno sviluppatore web.

  1. Sviluppare applicazioni web significa costruire software utilizzando degli standard (URI, HTTP, HTML, ecc.) che pertanto devono essere sufficientemente conosciuti.
  2. Questi standard costituiscono le interfacce generiche utilizzate da tutti i componenti della rete (server, browser, motori di ricerca, proxy, ecc.). Se questi standard non vengono rispettati dal nostro applicativo, qualche componente smetterà di funzionare correttamente.
  3. Gli standard del Web si ispirano al modello REST per raggiungere gli obiettivi che questa architettura si pone. Rispettare questi standard consente alle nostre applicazioni di raggiungere gli stessi obiettivi senza dover introdurre specifiche soluzioni.

__

  • A ben vedere neanche gli standard URI e HTTP rispettano perfettamente il modello REST. Infatti in un URL è possibile inserire lo username e la password del client per accedere a risorse protette da meccanismi di sicurezza. Ma gli identificativi delle risorse REST devono contenere solo informazioni relative al server, non al client. Anche i cookie dell’HTTP non rispettano il modello REST, infatti contengono dati associati non ad un singolo URL ma a tutti gli URL di un determinato percorso. Questi dati poi non sono semanticamente strutturati e pertanto risultano potenzialmente pericolosi. Con essi infatti è possibile tracciare la navigazione di un utente.