martedì 19 novembre 2013

Chiamate AJAX cross domain JQuery ad API JSON

Ultimamente i progetti web-based sono strutturati tutti in modo simile, ossia con un backend API e un frontend che interroga le API, solitamente in ajax.
In particolare i miei progetti sono caratterizzati da PHP + CodeIgniter lato API (con risposte JSON), e jQuery lato frontend.
Il jQuery si comporta magnificamente con le chiamate Ajax, ma qualche giorno fa mi è capitato il caso di interrogare le API da un dominio diverso da quello del server dove risiedono. Il problema è relativo al fatto che jQuery non permette chiamate ajax cross-domain con tipologia JSON oppure testo normale, come restrizione di sicurezza.
Leggendo la documentazione, viene specificato che le chiamate cross-domain sono possibili solo per la tipologia di scambio dati JSONP.
Ma che diavolo è JSONP? Il fantomatico JSON with Padding è un formato di interscambio dati basato su due semplici punti:
- una funzione di callback
- come parametro della precedente, il JSON che intendiamo trasmettere.
Ad esempio, questo è JSONP
funzionecallback({"status":"ok"})
Mentre il rispettivo JSON sarebbe
{"status":"ok"}
La funzione di callback lato client si può specificare mediante un apposito comando di configurazione di $.ajax oppure lasciare che sia jQuery a decidere il nome della callback ed a inviarlo come parametro GET (chiamato appunto, callback) alle API.
Vediamo quindi nel dettaglio come gestire le nozioni precedentemente apprese. Lato API, vediamo un semplice esempio in cui vogliamo come output un oggetto di prova contenente id e descrizione:
$obj = new stdClass();
$obj->id = "56321564";
$obj->descrizione = "Prova di descrizione";

if ($_GET['callback']!='') {
    echo $_GET['callback'].'('.json_encode($obj).')';
} 
else {
    echo json_encode($obj);
}
In questo modo siamo in grado di capire in maniera molto semplice (senza header http) in che formato mostrare il risultato: se esiste un parametro GET chiamato callback, lo script deve utilizzare il formato JSONP, altrimenti il JSON normale.
Ed ora la parte frontend, in jQuery:
var apiUrl = "http://www.example.com/api/example.php";
$( document ).ready(function() {
    $.ajax({
        type: "GET",
        url: apiUrl,
        dataType: "jsonp" ,
        crossDomain: true,
    }).done(function( json_response ) {
        console.log(JSON.stringify(json_response));
    }).fail(function(jqXHR, textStatus) {
        $('#result').html( "Request failed: " + textStatus + " " + jqXHR.status );
    });

});
La quale produrrà il risultato voluto in console:
{"id":"56321564", "descrizione": "Prova di descrizione"}
Importanti sono l'opzione dataType nella chiamata Ajax impostata su jsonp e crossDomain impostato su true.

Nessun commento: