Utiliser JSON comme format d'échange de données, avec prototype.js

27 janvier 2007Ajax, JSON, prototype.js
 Cet article a été rédigé il y a plusieurs années et peut ne plus être tout à fait à jour…

Nous avons vu comment réaliser une première requête Ajax en utilisant prototype.js, et comment utiliser JSON comme format d'échanges de données lors d'une requête Ajax utilisant directement l'objet XMLHttpRequest.

A présent, nous allons voir comment nous pouvons mettre ces connaissances "en commun", et utiliser JSON comme format d'échange de données lorsque l'on développe avec le framework Prototype.

Principe de fonctionnement

Un bref rappel sur le principe de fonctionnement :

  • Une page HTML contenant, pour notre exemple, un lien appelant une fonction nommée gestionClic, qui sera chargée de lancer la requête Ajax et gérer son retour.
  • Quelques lignes de JavaScript, réalisant l'appel Ajax et obtenant la réponse du serveur.
  • Et un programme côté serveur (encore une fois, j'utiliserai du PHP), chargé du traitement déclenché par la requête Ajax.

Puisque c'est le but de cet article, le format de données utilisé en sortie par le programme côté serveur sera JSON.

Page HTML

Pour commencer, voici à quoi peut ressembler notre page HTML :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
    <title>AJAX : Exemple de client</title>
    <script type="text/javascript" src="prototype-1.5.0.js"></script>
    <script type="text/javascript" src="test2.js"></script>
</head>
<body>
    
    <p>
        <a href="" onclick="gestionClic(); return false;">
            Cliquez ici !
        </a>
    </p>
    
    <div id="resultat">&nbsp;</div>
    
</body>
</html>

Et la fonction gestionClic, appelée lors d'un clic sur le lien, peut être la suivante :

function gestionClic()
{
  var url = './test2.php';
  var myAjax = new Ajax.Request(
      url,
      {
        method: 'get',
        onComplete: gestionReponse
      });
} // gestionClic()

En cas de clic sur le lien, une requête HTTP est envoyée en GET à la page test2.php.

Une fois la réponse reçue, la fonction gestionReponse est automatiquement appelée pour la traiter.
Par la suite, nous allons travailler au développement de cette fonction.


JSON en responseText

Nous avons vu lors d'un précédent article que l'on peut, avec le programme côté serveur, écrire des données JSON sur la sortie standard ; par exemple, pour renvoyer la liste de trois des noms de trois auteurs de PHP :

<?php
    header('Content-Type: text/html; charset: UTF-8');
    echo '[{"nom": "Lerdorf", "prenom": "Rasmus"}, {"nom": "Gutmans", "prenom": "Andi"}, {"nom": "Suraski", "prenom": "Zeev"}]';
?>

Ce qui est écrit sur la sortie standard du programme serveur est reçu comme corps de la réponse HTTP, et est accessible via la propriété responseText de l'object XMLHttpRequest.

L'instance d'objet XHR utilisé pour effectuer la requête Ajax est passé par prototype.js en premier paramètre de la fonction appelée à la fin de celle-ci.

En evaluant le contenu de la propriété responseText de cet objet, on reconstitue, côté JavaScript, l'objet renvoyé par le serveur.

Par exemple, pour afficher les noms des trois personnes renvoyées par le programme PHP présenté juste au-dessus :

function gestionReponse(xhr)
{
    var personnes = eval('(' + xhr.responseText + ')');
    if (personnes)
    {
        var str = '';
        for (var i=0 ; i < personnes.length ; i++)
        {
            var personne = personnes[i];
            str += personne.prenom + ' ' 
                   + personne.nom + '<br />';
        }
        $('resultat').innerHTML = str;
    }
}

Nous commençons par evaluer les données au format JSON renvoyée par le serveur, puis, si cette evaluation s'est bien passée - la liste des personnes n'est pas vide - nous parcourons la liste, en vue d'obtenir les noms et prénoms de chacun... Et pour finir, nous affichons le résultat.

Ce qui affichera, comme attendu :

Rasmus Lerdorf
Andi Gutmans
Zeev Suraski

Mais le framework prototype.js permet d'automatiser ces traitements, afin de diminuer votre charge de travail...


Prototype.js et JSON

Prototype.js permet d'automatiser un peu ceci : si la réponse HTTP contient un en-tête nommé X-JSON, le contenu de celui-ci sera extrait, automatiquement evalué, et sauvegardé comme un objet.

Cet objet sera alors passé en second paramètre à la fonction déclenchée à la réception du résultat - notre fonction gestionReponse.

Code PHP

A titre d'exemple, voici le code d'un programme PHP écrivant notre liste d'auteurs dans un en-tête HTTP nommé X-JSON, plutôt que sur la sortie standard :

<?php
    header('Content-Type: text/html; charset: UTF-8');
    $str = '[{"nom": "Lerdorf", "prenom": "Rasmus"}, {"nom": "Gutmans", "prenom": "Andi"}, {"nom": "Suraski", "prenom": "Zeev"}]';
    header('X-JSON: ' . $str);
?>

Récupération et utilisation des données

Et côté JavaScript :

  • Le second paramètre reçu par la méthode de gestion de la réponse est l'objet reconstitué.
  • Nous pouvons l'utiliser comme si nous avions appelé eval nous même.
  • Il ne faut pas appeler eval nous-même sur les données de l'en-tête X-JSON : cela reviendrait à l'appeler deux fois, puisqu'il est déjà exécuté par prototype.js, ce qui causerait une perte de temps et de performances !

Pour exemple (notez la présence du second paramètre) :

function gestionReponse(xhr, personnes)
{
    if (personnes)
    {
        var str = '';
        for (var i=0 ; i < personnes.length ; i++)
        {
            var personne = personnes[i];
            str += personne.prenom + ' ' 
                   + personne.nom + '<br />';
        }
        $('resultat').innerHTML = str;
    }
}

Nous commençons par vérifier que l'objet a bien été evalué ; et si oui, nous l'utilisons, exactement comme nous l'avons fait plus haut.


Pour information, plutôt que de parcourir la liste de personnes "à la main", nous pouvons exploiter le fait que, lorsque l'on utilise prototype.js, les listes sont automatiquement étendues en objets Enumerable.

Cela signifie, entre autre, qu'on peut les parcourir à l'aide de la méthode each, qui permet d'exécuter une fonction sur chaque élément de la liste :

function gestionReponse(xhr, personnes)
{
    var str = '';
    personnes.each( 
        function (personne)
        {
            str += personne.prenom + ' ' 
                   + personne.nom + '<br />';
        });
    $('resultat').innerHTML = str;
}

Pour plus d'informations à ce sujet, n'hésitez par à consulter la documentation de l'API de prototype.js !


Évaluation automatique de JavaScript

Il reste encore une fonctionnalité de prototype.js dont je souhaite parler dans cet article :

Si le Content-Type de la réponse renvoyée par le serveur est un de ceux que prototype.js reconnaît comme indiquant du JavaScript, alors, le code retourné sera automatiquement evalué.

Cela signifie deux choses :

  • Le code JS renvoyé par le serveur sera exécuté (Je l'ai déjà dit juste en-dessous, mais c'est suffisament important et/ou impactant - ne serait-ce qu'en terme de sécurité - pour que j'insiste).
  • Vous n'avez pas besoin de gérer vous-même la réponse à votre requête.

Par exemple, si le code de votre programme côté serveur, appelé par votre requête Ajax, est le suivant :

<?php
    header('Content-Type: text/javascript; charset: UTF-8');
    echo "alert('bouh !');";
?>

Le Content-Type renvoyé par le serveur sera "text/javascript" - qui est l'un de ceux reconnus par prototype.js.

En admettant que votre appel soit fait de la manière suivante :

function gestionClic()
{
  var url = './test2.php';
  var myAjax = new Ajax.Request(
      url,
      {
        method: 'get'
      });
} // gestionClic()

Le code alert('bouh !'); sera exécuté au retour de la requête... Un message s'affichera à l'utilisateur.

Note : Si tout ce que nous voulons faire est exécuter le code JavaScript généré par le serveur, il n'est même pas nécessaire de définir une fonction gérant le retour de la requête (branchée sur l'événement onComplete, par exemple) ; c'est ce que j'ai fait ici, d'ailleurs.

Liste des Content-Type reconnus par prototype.js

Pour que les données renvoyées par le serveur soient interprétée comme étant du code JavaScript, et que celui-ci soit evalué, le Content-Type de la réponse HTTP doit être un des suivants :

  • application/ecmascript
  • application/javascript
  • application/x-ecmascript
  • application/x-javascript
  • text/ecmascript
  • text/javascript
  • text/x-ecmascript
  • text/x-javascript


Je n'ai jusqu'à présent encore jamais réellement utilisé la fonctionnalité d'évaluation automatique de code JavaScript... Mais l'évaluation automatique de données JSON, par contre, elle, est un réel plus ; nous serons sans aucun doute amenés à l'utiliser à l'avenir, au cours de futurs articles.


MAJ 03/04/2008 : Ajout en pièce jointe à l'article d'une archive contenant un exemple complet