Quand elle entend le tocsin qui sonne, la mignonne hérissonne friponne frissonne
Par Clochix le lundi 27 avril 2009, 23:48 - Technoweb - Lien permanent
Ayant vu passer quelques annonces intéressantes sur JSON ces derniers jours, j'ai un peu gratté et ai découvert tout un écosystème foisonnant de projets autour de ce format que je croyais connaître. J'ai l'impression de voir depuis quelques mois la même agitation autour de JSON qu'autour d'XML il y a une dizaines années. Des propositions de spécifications, mais aussi des implémentation et du vrai code, preuves que le format a le vent en poupe, même si Ajaj n'est sans doute pas près de détrôner Ajax dans la liste des prénoms préférés des développeurs Web.
Je vais donc essayer le temps de deux ou trois rapides billets de partager quelques-unes de mes découvertes. Ces billets seront largement inspirés des travaux de Kris Zyp, Stefan Goessner et bien sûr Douglas Crockford, gourou JavaScript et père de JSON.
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 ?
Commentaires
J'ai remonté il y a quelques temps ce qui me semble être un bug dans l'implémentation json-rpc du framework zend, mais apparemment ça ne se bouscule pas sur la question: http://framework.zend.com/issues/br...