Pubblichiamo un servizio tramite JSON-RPC con Zend Framework

Logo JsonIn ambito di calcolo distribuito e sempre più orientato ai servizi web non si può non nominare qualche tecnica di chiamate a procedure remote (RPC: Remote Procedure Call).

RPC si riferisce all’attivazione di una procedura su una macchina remota a seguito di una richiesta effettuata attraverso la rete. Gli standard più diffusi al momento sono sicuramente SOAP e XML-RPC, ma questi stanno, nell’ultimo periodo, perdendo terreno rispetto al più giovane JSON-RPC (Vedi il neanche tanto recente ritiro delle API SOAP da parte di google).

Come suggerisce il nome, JSON-RPC è una tecnica di RPC basata sul formato di interscambio dati JSON, tanto utilizzato nei moderni siti internet con javascript e le chiamate AJAX.

L’Applicazione di Esempio

Per mantenere le cose il più semplici possibile, realizzeremo una pagina web che contiene un solo articolo, con titolo, data e testo, letto da un file (niente database).
Tramite JSON-RPC sarà possibile leggere e scrivere da remoto il contenuto di questo file, aggiornando così la pagina web.

L’esempio conterrà in sostanza 3 file, oltre allo Zend Framework che utilizzeremo per implementare Client e Server JSON-RPC:

  • index.php: Visualizza la pagina con l’articolo
  • json-rpc.php: Script che implementa il server JSON-RPC
  • article.json: Il nostro storage che conterrà i dati dell’articolo

La Homepage

La homepage sarà semplicissima, legge il contenuto del file article.json e lo visualizza:

[php]
<?php
$article = json_decode(file_get_contents("article.json"), true);
?>
<!DOCTYPE html>
<html>
<head><title>Test JSON-RPC</title></head>
<body>
<h1><?=$article[‘title’]?></h1>
<h5><?=$article[‘date’]?></h5>
<p><?=$article[‘content’]?></p>
</body>
</html>
[/php]

Mentre il contenuto di article.json potrebbe essere qualcosa di simile a:

[javascript]
{
"title": "Test",
"date": "13/01/2011",
"content": "<p>Testo di prova</p>"
}
[/javascript]

Il Server JSON-RPC

Grazie alla potenza della classe Zend_Json_Server, implementare un server JSON-RPC è semplicissimo.
E’ sufficiente definire la classe PHP con i metodi pubblici da rendere disponibili da remoto e passarla come parametro a Zend_Json_Server, che ne leggerà i metodi e creerà automaticamente la definizione del servizio.

Quello che ci resta da fare è gestire le richieste. Le chiamate JSON-RPC devono avvenire necessariamente in POST, per cui se la richiesta è in GET, forniremo la definizione del servizio:

[php]
<?php
// Inizializzo l’ambiente caricando lo zend framework
error_reporting(E_ALL);
require_once "Zend/Loader.php";

Zend_Loader::loadClass("Zend_Loader_Autoloader");
Zend_Loader_Autoloader::getInstance();

// Definisco la classe che legge e scrive il file con l’articolo
class ArticleUpdater {
protected static $storage = ‘article.json’;

public function set($title, $date, $content) {
file_put_contents(self::$storage, json_encode(array(
‘title’ => $title,
‘date’ => $date,
‘content’ => $content
)));
}

public function get() {
return json_decode(file_get_contents(self::$storage), true);
}
}

// Server JSON
$server = new Zend_Json_Server();
$server->setClass(‘ArticleUpdater’);

if ($_SERVER[‘REQUEST_METHOD’] == ‘GET’) {
$server->setTarget(‘/json-rpc.php’)
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);

header(‘Content-Type: application/json’);
echo $server->getServiceMap();
return;
}

$server->handle();
[/php]

Ovviamente perché questo script funzioni è necessario aver installato lo Zend Framework in una cartella nell’include_path o nella stessa cartella dell’applicazione. Il pacchetto minimal è più che sufficiente.
Impostiamo inoltre i necessari permessi di scrittura al file article.json (666) per poter consentire al metodo set di modificarne il contenuto.

Client remoto (Consumer)

Purtroppo lo Zend Framework non ci fornisce l’implementazione Zend_Json_Client che ci aspetteremmo, ma realizzare un semplice client PHP tramite CURL non è troppo complicato.

Creiamo quindi una semplice funzione per “consumare” un servizio JSON-RPC. I parametri necessari sono l’url del server e il nome del metodo da chiamare. I parametri sono invece opzionali.

[php]
function json_rpc_call($url, $method, $params=null) {
$request = array(
‘method’ => $method,
‘id’ => 1
);
if (is_array($params))
$request[‘params’] = $params;
$request = json_encode($request);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
‘Content-Type: application/json’,
‘Content-Length: ‘ . strlen($request) . "\r\n",
$request
));
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
curl_close($ch);

$output = json_decode($output, true);

if (!is_null($output[‘error’]))
throw new Exception($output[‘error’][‘message’]);

return $output[‘result’];
}
[/php]

La funzione restituisce il parametro “result” della risposta se tutto ha funzionato correttamente, altrimenti lancerà un’eccezione col messaggio d’errore restituito dal server.
Un test d’uso quindi potrebbe essere questo:

[php]
try {
var_dump(json_rpc_call("http://localhost/json-rpc.php", "get"));
var_dump(json_rpc_call("http://localhost/json-rpc.php", "set", array("Nuovo titolo", "17/01/2011", "Nuovo testo dell’articolo")));
var_dump(json_rpc_call("http://localhost/json-rpc.php", "get"));
} catch (Exception $e) {
echo "JSON-RPC call failed with message: {$e->getMessage()}";
}
[/php]

Ovviamente nulla ci vieta di chiamare le funzioni RPC direttamente da javascript o da qualsiasi altro linguaggio di programmazione. Ad esempio per MooTools, è disponibile una classe apposita sul Forge.

Il codice dell’articolo è disponibile per il download.

Condividi