Nella scorsa lezione abbiamo approntato la nostra prima semplice API, accessibile tramite un URL che segue lo schema http://server:xxx/api/items/yyy
. Ad esempio, se la nostra applicazione è pubblicata sulla macchina di sviluppo alla porta 1039
, potremmo aprire un browser e farlo puntare all'indirizzo http://localhost:1039/api/items/API
per ottenere un risultato analogo al seguente:
In questo caso abbiamo ottenuto una rappresentazione della risorsa in XML, ma altri client potrebbero richiedere una rappresentazione in altri formati specificandola tramite l'header HTTP Accept impostato al valore application/json.
Accedere ad una Web API tramite un browser non è però la situazione standard. Un Web service normalmente è pensato per essere utilizzato via codice. Vediamo quindi come sfruttare la nostra API tramite JavaScript e realizzare una semplice pagina Web per la consultazione del nostro glossario.
Nel nostro esempio utilizzeremo jQuery, ma è possibile utilizzare una qualsiasi libreria per interrogare via Ajax la Web API.
Creiamo quindi una pagina HTML con una semplice casella di testo ed un pulsante:
<div>
<label for="termine">Inserisci il termine da ricercare</label>
<input id="termine" type="text" />
<button onclick="findItem();">Cerca</button>
</div>
Inseriamo un riferimento a jQuery e implementiamo la funzione findItem()
che si occuperà di interrogare la nostra API e di visualizzare il risultato:
function findItem() {
var id = $('#termine').val();
$.getJSON("api/items/" + id,
function (data) {
var str = '<p><b>' + data.term + '</b><br/>' + data.definition + '</p>';
$('#divDefinizioni').html(str);
}).fail(
function (jqXHR, textStatus, err) {
$('#divDefinizioni').html('Error: ' + err);
});
}
Inserendo un termine e cliccando sul pulsante Cerca l'utente otterrà la relativa definizione o un messaggio di errore nel caso in cui il termine non esiste nel glossario.
Nel caso di client JavaScript occorre tener presente le problematiche relative alla chiamate cross-domain. Nel nostro esempio non c'è nessun problema in quanto client e API appartengono allo stesso dominio, ma nel caso in cui si voglia chiamare tramite JavaScript una API appartenente ad un dominio diverso occorre prendere in considerazione le limitazioni imposte dalle politiche di sicurezza dei browser. Naturalmente per altri tipi di client REST questa problematica non si pone.
Dietro le quinte: convenzioni
Nella descrizione generale del funzionamento interno del framework abbiamo detto che una risorsa viene individuata tramite un URI e che, in base al metodo HTTP ed agli eventuali parametri, viene individuato il metodo del relativo controller da invocare. Ma come fa il framework ad individuare la risorsa corretta? Come fa a sapere qual è il controller associato e che un suo determinato metodo corrisponde al metodo HTTP specificato dal client?
Il funzionamento del sistema è basato su alcune convenzioni predefinite, che comunque possono essere personalizzate in base alle proprie esigenze, come vedremo più avanti nella guida.
Lo schema dell'URI
La prima convenzione è quella che riguarda lo schema dell'URI per individuare una risorsa. Se andiamo a curiosare nel Global.asax della nostra applicazione scopriremo che è stata definita una route come la seguente:
/api/{controller}/{id}
La route definisce uno schema di URL con {controller}
e {id}
come segnaposto per il controller della risorsa e l'eventuale identificatore.
Alla ricezione di una richiesta HTTP, il sistema analizzando l'URL andrà alla ricerca di un controller per la risorsa specificata. L'individuazione del controller viene effettuata concatenando al nome indicato al posto di {controller}
con la parola chiave controller. Quindi, facendo riferimento al nostro esempio, per gestire l'URL /api/items/API
, il sistema cercherà un controller con nome ItemsController
.
Per capire quale metodo del controller invocare, il sistema fa riferimento al metodo HTTP utilizzato dal client. In pratica, se il client ha utilizzato il metodo GET, il sistema andrà alla ricerca di un metodo del controller il cui nome inizia proprio con get, individuando nel nostro caso il metodo GetItemByTerm()
. Lo stesso meccanismo sarà valido per i metodi PUT
, POST
e DELETE
.
Nel caso di più metodi che iniziano con lo stesso prefisso, il framework individuerà quello corretto analizzando il numero ed il tipo di parametri previsti dal metodo e confrontandoli con gli argomenti passati dal client.
Nel nostro esempio, il valore associato a {id}
viene assegnato al parametro id di GetItemByTerm()
.