Avant d'entrer dans le vif du sujet, petit rappel sur le format lui-même.

Rappel

JSON est un format de données à la syntaxe très proche de celle de JavaScript[1], et donc idéal pour échanger des données avec des scripts JS. Il fera d'ailleurs partie de la prochaine spécification du langage[2] et la plupart des navigateurs modernes savent manipuler nativement des objets en JSON. C'est un format très simple, relativement lisible tout en étant peu verbeux et donc compact, généralement plus que XML (par contre, à la différence d'XML il n'est pas Xtensible). Encoder des données en JSON et les ré-interpréter est trivial, ce qui est sans doute une des clés de sa rapide extension.

JSON-RPC, pour appeler des procédures distantes

XML-RPC a désormais son pendant, JSON-RPC, qui comme son nom l'indique utilise JSON pour transporter les informations lors d'appel de procédures distantes entre des serveurs. Il est sans état (stateless) et indépendant de la couche transport. Une première spécification, utilisant HTTP pour la couche transport a été adoptée, et une deuxième version est en cours de finalisation. La première version de la spécification décrivait des conversations entre deux pairs capables chacun d'émettre des requêtes et d'y répondre. Pour se placer davantage dans un contexte web, la deuxième version a gommé le côté bi-directionnel et parle à présent explicitement de client et de serveur.

JSON-RPC est un protocole très simple, et beaucoup de projets l'utilisent sans doute sans savoir qu'il a été normalisé (Couac par exemple ;) ). Les spécifications définissent le format des requêtes et des réponses. Il définit également un type particulier de requête, les notifications, qui n'attendent pas de réponse. Dans la première version de la spécification, les paramètres étaient transmis dans un tableau et identifiés par leur ordre. La deuxième permet également d'utiliser des paramètres nommés, en les passant dans un objet.

De très nombreuses implémentations existent, dans de nombreux langages. Par exemple en PHP la classe jsonrpc2 du Zend Framework. Malheureusement, le site json-rpc.org qui hébergeait de nombreuses ressources sur le sujet, et par exemple Jsolait, une bibliothèque JavaScript, semble être temporairement hors ligne.

Donner une adresse avec JSONPath

JSONPath est l'équivalent de XPath: une syntaxe pour désigner une portion d'un document JSON. Compte tenu de la proximité avec JavaScript, la syntaxe est triviale: on peut désigner le titre du premier livre en magasin par $.store.book[0].title ou $['store']['book'][0]['title'], $ désignant la racine de l'objet. JSONPath implémente une partie de la syntaxe et des fonctions de XPath. Par exemple $.store.book[(@.length-1)].title désignera le titre du dernier livre de la liste.

Stefan Goessner fournit des implémentations de JSONPath en JavaScript et en PHP, et Kris Zyp l'a intégré à Dojo. Un plugin jquery est également en cours de développement.

JSONQuery, pour faire des recherches

Si JSONPath permet d'utiliser des filtres, il reste difficile de l'utiliser pour écrire des requêtes plus complexes. Kris Zyp l'a donc étendu sous le nom de JSONQuery. JSONQuery est un langage permettant de rechercher des informations à l'intérieur d'une structure encodée en JSON. Il se base sur JSONPath, comme XQuery étend XPath. Quelques exemples pour mieux comprendre:

  • il utilise des expressions pour filtrer les tableaux. par exemple [?price < 15 & rating > 3] extraira d'un tableau d'objets tous ceux qui ont un prix inférieur à 15 et une note supérieure à 3;
  • on peut trier les résultats: [/lastName,/firstName] triera les objets contenus dans un tableau en fonction de leur nom puis de leur prénom;
  • modifier les résultats en appliquant un mapping aux éléments d'un tableau est tout aussi simple: [={price:price,name:firstName + " " + lastName}] retournera un tableau d'objets dont le nom sera la concaténation des noms et prénoms des objets originaux;
  • les différentes opérations sont évidemment combinables : $.products[?price < 15][\rating][0:20] retournera les 20 premiers objets dont le prix est inférieur à 15, triés en fonction de leur note; pour obtenir le prix le plus élevé, on utilisera la requête $.store.book[/price][0].price

J'ai trouvé deux implémentations de JSONQuery, l'une intégrée aux modules complémentaires de Dojo, l'autre en JavaScript natif semble être une transcription de la précédente sans dépendance à Dojo.

Avec l'arrivée de bases de données basées sur JSON que j'évoquerai dans un prochain billet, JSONQuery pourrait être le prochain SQL.

Utiliser des références internes ou externes avec JSON Referencing

Parfois on voudrait stocker dans un objet une référence à un autre objet, un pointeur ou un lien (indispensable par exemple lorsqu'on sérialise des objets qui ont des références croisées). C'est l'objet de la proposition JSON Referencing, toujours de Kris Zyp. Il propose de stocker toutes les références dans des objets comportant une seule propriété nommée $ref. Cette propriété peut prendre trois types de valeur:

  • un identifiant. Dans ce cas, les différents objets contenus dans la structure JSON doivent comporter un champs "id" unique. Par exemple, dans l'objet :
{"name":"Kris",
  "father":{
    "name": "Bill",
    "id":"1",
    "wife":{"$ref":"2"}
  },
  "mother":{
    "name":"Karen",
    "id":"2"
  }
}

la référence permet d'indiquer que l'épouse de Bill est Karen;

  • un chemin, le "$" servant à désigner la racine de l'objet sérialisé. L'exemple précédent s'écrit alors
{"name":"Kris",
 "father": {
   "name":"Bill",
   "id":"1",
   "wife": {"$ref":"$.mother"}
 },
 "mother": {
   "name":"Karen",
   "id":"2",
   "son": [
     {name: "toto"},
     {name: "titi"},
     {name: "tata"},
     {"$ref" : "$"}
   ]
 }
}
  • l'URI d'un objet distant : {"$ref": "http://toto.org/object/id/42"}
  • on peut enfin utiliser une combinaison d'un id pour désigner une racine et d'un chemin relatif, en utilisant la syntaxe JSONPath, comme par exemple {"$ref":"2.son[3]"} désignerait "tata";

Cette syntaxe permet de faire des références à l'intérieur d'un même objet, mais Krys propose d'aller plus loin en permettant les références entre plusieurs objets, via leur id. Dans ce cas, l'application doit maintenir un index des objets disponibles et de leur identifiant.

Kris a modifié le script "historique" de sérialisation/désérialisation de JSON afin de lui ajouter le support des références. Cette version est aujourd'hui intégrée à Dojo et je pense que c'est à présent cette version qui devrait faire foi. Elle permet entre autre de faire du lazy loading, c'est à dire de référencer des objets qui ne sont pas encore chargés et de les charger à la volée, uniquement lorsque qu'on en a besoin. Elle gère également le chargement d'objets distants référencés par leur URI.

JSPON, gérer la persistance d'objets

Puisque JSON Referencing permet de référencer des objets distant, Kris a ensuite imaginé de le combiner avec une architecture REST pour inventer un système de persistance d'objets, qu'il a nommé JSPON, pour JavaScript Persistent Object Notation. Persevere, un projet libre initié par Kris, en est une implémentation. C'est un serveur écrit en Java gérant la partie serveur de la persistance. Il permet les mécanismes standards de CRUD via les méthodes REST (POST, GET, PUT, DELETE). Persevere fait l'interface entre des objets JavaScript clients et des objets serveurs stockés dans des bases de données, des fichiers XML, exposés par d'autres applications, etc.

Persevere utilise JSONQuery et JSONPath, implémente le protocole de Bayeux pour "pousser" des objets sur le client, garantit l'intégrité et la validation des objets grace à JSON Schema, etc. Il mériterait un article complet à lui seul.

Vous en voulez encore ?

  • JSONT est le pendant de XSLT. Stefan Goessner a proposé dans un article un ensemble de règles permettant de traduire facilement des données de JSON à XML. Stefan a également développé une classe JavaScript pour réaliser ces transformations;
  • JSON offrant une syntaxe plus compacte que XML, le projet JsonML propose de l'utiliser pour transporter des données XML;
  • JSON Template, un langage de template implémenté en Python ou JavaScript;
  • et bien d'autres, mais je pense avoir fait le tour des principaux projets autour de JSON, à l'exception de JSON Shema dont je parlerai dans le prochain billet.

Quelques outils pour jouer avec JSON

  • Benjamin Hollis a créé JSONView, une extension pour Firefox permettant d'afficher les fichiers JSON dans votre navigateur au même titre que les fichiers XML, avec coloration syntaxique, gestion du folding[3], etc. Plus de détails sur son blog;
  • même chose avec JSONovich de Michael J. Giarlo;
  • Firebug 1.4 permettra d'afficher plus joliment les réponses du serveur encodées en JSON. Enfin pour l'instant ça marche quand ça veut.

Et en PHP ?

L'extension PECL JSON a été inclue à PHP 5.2, elle fait donc à présent partie intégrante du langage. Le prochain PHP 5.3 verra l'arrivée d'une fonction json_last_error pour obtenir le code retour de la dernière opération de sérialisation / désérialisation de JSON. C'est très basique, on aura le choix entre "pas d'erreur", "objet trop profond", "erreur d'encodage" et "erreur de syntaxe". Espérons qu'une prochain version de cette fonction permettra de récupérer également le contexte de l'erreur. json_encode gagne également avec PHP 5.3 un second paramètre, permettant de préciser des options de conversion PHP => JSON.

Pour aller plus loin, on pourra par exemple utiliser la bibliothèque Zend_Json du Zend Framework. Elle fournit entre autres une fonction pour convertir un objet de XML en JSON, et surtout une implémentation des deux versions de la spécification JSON RPC. Le framework Solar propose également un module Solar_Json.

Conclusion provisoire

Bien sûr, tout cela n'a rien de révolutionnaire. C'est pour l'essentiel la transcription en JSON d'outils existant depuis longtemps en XML. Mais par sa consanguinité avec JavaScript, je pense que JSON a de bonnes chances de s'imposer comme le format du Web des applications (XML sera celui du Web sémantique). Pour l'instant, il était essentiellement utilisé comme format d'échange dans le cadre de requêtes AJAX. Avec l'arrivée des bibliothèques que j'évoque ci-dessus, son champs d'utilisation s'élargit, on peut commencer à l'utiliser pour faire de plus en plus de choses. A vous de les inventer...

Notes

[1] la signification de l'acronyme est d'ailleurs JavaScript Object Notation

[2] au passage et pour faire suite à mon billet sur Harmony, l'Ecma a annoncé que la prochaine version de la norme ECMA-262 était à présent finalisée et serait probablement définitivement adoptée avant la fin de l'année sous le nom d'ECMAScript 5 (après s'être successivement appelée ES 3.1 puis Harmony). Cette révision est le fruit d'un compromis avec Microsoft, qui s'opposait aux beaucoup plus ambitieux travaux sur une version 4.0. Microsoft confirmait là une fois de plus son statut de principal frein à l'innovation sur le Web

[3] au secours, comment on dit en français ?