Alla scoperta del mondo delle applicazioni RESTful.
Approfittando del fatto di dover imparare le novità di rails 2.0 (e 2.1) ho pensato di concentrarmi 10 minuti sulle applicazioni RESTful, di fatto una delle caratteristiche più appetitose di Rails e su cui fin'ora non avevo indagato più di tanto.
Ma cosa vuol dire REST?
Per la precisione vuol dire Representational state transfer, ovvero un'architettura software basata sul concetto fondamentale di risorsa e implementa il protocollo HTTP nella sua interezza.
Chiunque abbia una minima conoscenza di html conosce i metodi GET e POST, sicuramente avrete creato un form inviato via post o digitato un url nella barra indirizzi inviando una richiesta via get. Ma il protocollo HTTP ha ulteriori due metodi: PUT e DELETE.
Il primo serve a modificare una risorsa, la seconda per cancellarla. In realtà i browser non implementano questi metodi e Rails sopperisce a questa mancanza gestendo i metodi PUT e DELETE simulandone il comportamento via POST.
A cosa ci serve tutto questo? Il principio è semplice: ogni risorsa è identificata univocamente da un indirizzo, le operazioni da fare su di essa vengono identificate dai metodi con cui sono chiamate.
Per capire meglio il meccanismo generiamo tramite scaffold una piccola applicazione REST che gestisca una tabella con solo 2 campi, per esempio titolo e descrizione di un progetto.
Creiamo l'applicazione RESTbook
rails RESTbook
Se avete la versione 1.2.6 potete usare lo scaffold_resource
script/generate scaffold_resource project name:string desc:text
Con la versione 2.0 di rails lo scaffold è stato sostituito con lo scaffold_resource, quindi non rimane che lanciare lo scaffold:
script/generate scaffold project name:string desc:text
Se usate sqlite lanciate direttamente la migration, se usate mysql create prima il db.
Diamo un'occhiata al file routes.rb dove troviamo la prima novità:
map.resources :projects
Ovvero Rails ha mappato il nostro progetto come risorsa.
i Rest URL
Come sappiamo le routes incidono fortemente sugli url della nostra applicazione, in un'applicazione RESTful gli url non seguono più il modello /:controller/:action/:id, ma quello più semplice /:resource/:id, ogni azione che si riferisce a questa risorsa sarà richiamata tramite lo stesso url. Come fa il controller a "capire" quale azione intraprendere? Usando i metodi del protocollo HTTP:
| Metodo-REST | REST-URL | Metodo | URL |
| GET | /projects/1 | GET | /projects/show/1 |
| DELETE | /projects/1 | GET | /projects/destroy/1 |
| PUT | /projects/1 | POST | /projects/update/1 |
| POST | /projects | POST | /projects/create |
Il tutto sembra abbastanza complicato, ma in realtà non lo è.
Se nella barra degli indirzzo digito /projects/1 vuol dire che voglio vedere il progetto con id uguale ad 1. Se chiamo il DELETE sulla risorsa progetto con id=1 vuol dire che la voglio cancellare. Se mando un form tramite PUT vuol dire che voglio "mettere" i dati inseriti nella risorsa 1, ovvero voglio modificare e infine inviando un form via POST vuol dire che voglio postare un progetto, ovvero inserire.
i Controller REST
Una volta capito come funzionano gli URL diamo un'occhiata al controller.
Il codice dell'azione show è il seguente:
# GET /projects/1
# GET /projects/1.xml
def show
@project = Project.find(params[:id])
respond_to do |format|
format.html # show.rhtml
format.xml { render :xml => @project.to_xml }
end
end
Rispetto ad un controller classico troviamo una fondamentale differenza, ovvero la direttiva "respond_to". Questo meccanismo diventato di default in rails 2.0 e successivi serve a rispondere in maniera opportuna alle richieste effettuate. In questo esempio l'applicazione rispondere in html ad una richiesta html e in xml ad una richiesta in xml.
Volendo possiamo estendere questo comportamento per risponde ad altri formati come rss, atom e persino iphone.
Le view REST
I metodi redirect_to e link_to non sono adatti alle applicazioni rest in quanto prendono come parametri gli url classici controller/action/id. Dobbiamo quindi seguire una piccola convenzione richiamando degli helper autogenerati. In particolare:
| projects_path | /projects | GET | index |
| project_path(:id) | /projects/1 | GET | show |
| new_project_path | /projects/new | GET | new |
| edit_project_path(:id) | /projects/1/edit | GET | edit |
| projects_path | /projects | POST | create |
| project_path(:id) | /projects/1 | PUT | update |
| project_path(:id) | /projects/1 | DELETE | destroy |
New, Edit e Destroy
A prima vista le prime due azioni rompono il paradigma rest, ma l'impressione sparisce quando si considera che le azioni che presentano i form per inserire o modificare sono solo azioni preparatorie e che non fanno parte delle operazioni CRUD
Osserviamo ora i form per new ed edit.
New
form_for(:project, :url => projects_path) do |f| ...
=>
<form action="/projects" method="post">
Edit
form_for(:project, :url => project_path(@project),
:html => { :method => :put }) do |f| ...
=>
<form action="/projects/1" method="post">
<div style="margin:0;padding:0">
<input name="_method" type="hidden" value="put" />
</div>
Come sappiamo l'html supporta nativamente il metodo post, ma non il put. Rails simula il comportamento di PUT inserendo una input hidden chiamato _method con valore put e passa il tutto via post.
Destroy
Discorso analogo vale per DELETE. Anche in questo caso l'html non supporta nativamente questo metodo e rails risolve in maniera analoga:
link_to "Destroy", project_path(project), :method => :delete
=>
<a href="/projects/1"
onclick="var f = document.createElement(’form’);
f.style.display = ’none’; this.parentNode.appendChild(f);
f.method = ’POST’; f.action = this.href;
var m = document.createElement(’input’);
m.setAttribute(’type’, ’hidden’);
m.setAttribute(’name’, ’_method’);
m.setAttribute(’value’, ’delete’); f.appendChild(m);f.submit();
return false;">Destroy</a>
Conclusioni
In questo primo articolo su Rest ho cercato di dare una panoramica su questa metodologia di programmazione, c'è ancora tanto da dire, per esempio sulle risorse annidate, sui metodi "custom" e così via... mi riprometto di continuare il discorso nei prossimi articoli.


