InfoQ était au JUG Summer Camp 2013 à La Rochelle, et j'ai pu discuter avec Xavier Hanin de son dernier projet, RESTX.
Simon Baslé pour InfoQ : Xavier bonjour, pourrais-tu commencer par te présenter en quelques mots et présenter ton dernier projet, RESTX ?
Xavier Hanin : Bonjour ! Donc je suis Xavier Hanin, je suis développeur depuis 15 ans maintenant, et de manière non-professionnelle depuis plus longtemps que ça encore. Je travaille aujourd'hui dans une société qui s'appelle 4sh, c'est une petite société de services, et pour cette société-là je suis responsable de l'agence de Bordeaux. Ca ça ne me laisse pas toujours beaucoup de temps pour développer mais je continue à faire un petit peu d'architecture et de développement, spécialisé Java et Web. Et puis après, en termes d'historique, j'ai été notamment mis un petit peu sur le devant de la scène à l'époque où j'ai créé Ivy, qui est devenu plus tard Apache Ivy.
InfoQ : D'accord, et tu t'es lancé récemment dans un nouveau projet qui est RESTX. Est-ce que tu peux présenter celui-ci ? Quelle approche tu as eu pour ce projet ?
Xavier : Oui, alors RESTX c'est un tout nouveau projet commencé début 2013. Comme son nom l'indique un peu c'est un framework REST, framework ou librairie en fait car on peut l'utiliser vraiment comme quelque chose de complet (orienté framework) ou comme une simple librairie. C'est un framework REST en Java, avec pas mal de similitudes avec JAX-RS notamment.
InfoQ : Alors retour un peu aux bases. Qu'est-ce que c'est qu'être RESTful pour toi ? Quelle est ta philosophie derrière ce projet et en quoi se démarque-t'il d'autres frameworks REST ?
Xavier : Alors être RESTful, c'est difficile sur une courte interview de décrire ça... C'est un style d'architecture, imprégné par le Web, introduit par la thèse de Roy Fielding en 2000. Roy Fielding est cofondateur de la fondation Apache, du projet Apache HTTPD, et a participé au workgroup de spécification sur les URI, et sur HTTP aussi je crois... Donc, c'est vraiment un style d'architecture qui est très très proche du protocole HTTP, dans lequel on va manipuler des ressources par l'intermédiaire de leur représentation, et en identifiant ces ressources avec des identifiants de ressource que sont en général les URL, et avec un ensemble de contraintes appliquées là-dessus. Il y a 6 ou 7 contraintes au total pour dire que l'architecture est RESTful et va vraiment bénéficier du côté HTTP pour obtenir une très grande scalabilité notamment.
InfoQ : Le framework RESTX en fait permet d'embarquer un serveur quand on l'utilise comme un framework, on peut l'utiliser comme un tout finalement. Est-ce qu'on retrouve la même flexibilité que l'on pouvait trouver dans Ivy ? Est-ce que tu as eu un peu les mêmes approches pour le choix du serveur, le déploiement dans un AS sous forme de war, est-ce que c'est possible tout ça ?
Xavier : Alors oui c'est possible, pour répondre globalement aux différentes questions :) Il y a effectivement possibilité de lancer directement une application RESTX en utilisant un main fourni par RESTX qui va permettre d'embarquer un serveur, et là-dessus il y a déjà plusieurs possibilités offertes par RESTX : soit on va embarquer un serveur qui est un conteneur de Servlet (Jetty ou Tomcat sont supportés directement et intégrés en fait), soit il y a possibilité aussi de travailler avec un framework qui s'appelle SimpleFramework, qui est plus un serveur qu'un framework d'ailleurs. On peut donc faire tourner une application RESTX avec un serveur embarqué soit standard, soit Simple, et on peut créer des adaptateurs autres que çà. Sinon il est aussi possible de packager son application qui utilise RESTX comme un war et c'est donc supporté, après il suffit d'avoir un conteneur de Servlet 2.5 et Java 7, c'est aussi simple que çà.
Et après on peut aussi bien l'embarquer dans une application existante qui fasse d'autres choses. Au final, RESTX quand on veut l'embarquer dans un conteneur de Servlet, c'est juste la définition d'une Servlet particulière, donc on peut la monter simplement sur un chemin donné de notre application et tout à fait utiliser d'autres Servlets et d'autres filtres à d'autres niveaux.
InfoQ : Très bien. Donc on la monte sur une Servlet qui va être une sorte de racine pour le service REST dans l'application ?
Xavier : Voilà, RESTX, comme je l'ai dit, n'est pas en fait obligé de tourner dans un conteneur de Servlet, il n'y a donc pas d'adhérence à l'API Servlet et en fait il y a un adapter entre l'API Servlet et l'API RESTX. Donc, ce qu'on va monter quand on est dans un conteneur de Servlet, c'est simplement déclarer cette Servlet RESTX qui fait l'adaptateur et part sur le système de routage interne qu'il y a dans RESTX, puisqu'il y a un système de routage intégré vers les différents endpoints qu'on va définir.
InfoQ : D'accord, et d'ailleurs comment dans RESTX on définit cette API ? C'est un système d'annotations ?
Xavier : Oui, alors c'est assez proche de JAX-RS là-dessus. On va définir ses endpoints en définissant des classes Java sur lesquelles on va mettre des annotations. Ce sont des annotations propres au framework aujourd'hui, mais j'ai dans l'idée éventuellement de supporter les annotations JAX-RS, ce qui ne serait pas très compliqué en soi. Mais mon objectif était de simplifier un petit peu. Dans RESTX il y a un certain nombre de choix, notamment le fait d'utiliser comme représentation par défaut du json, et puis aussi de travailler avec de l'annotation processing et du coup pouvoir accéder à un certain nombre d'informations qui ne sont que dans les sources, comme les noms des paramètres dans les méthodes, les types génériques. Du coup, ça permet de mettre moins de choses dans les annotations et d'en avoir plus directement dans le code source.
InfoQ : Il y avait vraiment une volonté de faire du processing plutôt que des proxy, des bindings...
Xavier : Oui, ça c'est un point important. Un des points qui m'a vraiment invité à me lancer dans RESTX, c'est que je suis toujours à la recherche de performance et notamment de performance au start-up. J'aime les cycles de développement très très rapides. Je suis développeur Web aussi et sur le Web quand je fais des modifications dans les sources JavaScript, c'est instantané, je rafraîchis mon navigateur (ou même pas s'il y a du live-reload) et j'ai le résultat tout de suite. Pour moi un serveur qui démarre en plusieurs secondes c'est déjà trop, donc je voulais quelque chose qui démarre très vite... Et ce qui pénalise d'expérience les démarrages des serveurs c'est que beaucoup font du classpath-scanning. Ils commencent au démarrage de l'application par aller regarder à plein d'endroits : "ah tiens, est-ce qu'il y a une classe qui est annotée avec quelque chose ?". Et ça c'est assez coûteux, surtout quand l'application est de plus en plus lourde. Je préférais faire ces choses-là à la compilation plutôt qu'au runtime, et ça a d'autres avantages aussi puisqu'on voit les invocations, les analyses d'impact se font beaucoup mieux parce qu'on voit le code généré, qui est assez lisible en lui-même. Ce qu'on trouverait d'équivalent dans d'autres framework, en bytecode généré, là c'est du code source généré, on peut naviguer dedans, et quand on fait du debug avec du step into on ne rentre pas dans des proxy, du
java.lang.method.invoke
des choses comme ça.
InfoQ : Il y a pas mal aussi de fonctionnalités qui m'ont semblé liées à la qualité de vie du développeur : on a un système de plugins, une console d'administration intégrée, de la génération auto de documentation et de jeux de test... Est-ce que tu peux présenter rapidement ces fonctionnalités, comment tu as mis en place tout ça et la synergie entre ces features ?
Xavier : Effectivement c'est un focus important. J'ai fait RESTX pour m'amuser surtout et je m'amuse avec des outils qui répondent bien et qui offrent des services aux développeurs. Et donc je me suis pas mal concentré là-dessus. Il y a effectivement tout un jeu de fonctionnalités qui sont là pour faciliter la vie du développeur. Dans la dernière release il y a notamment un travail assez important qui a été fait sur tout ce qui est autocompilation et hot-compile/hot-reload, qui permet vraiment que, dès qu'on touche à un fichier côté serveur, il se recharge dans l'application, c'est intégré.
Il y a effectivement une console qu'on n'est pas obligé d'embarquer puisque effectivement RESTX est très modulaire. On a beaucoup de petits modules et il suffit d'inclure ces modules dans son application et on aura une console d'administration, qui elle-même est pluggable. On peut rajouter des éléments supplémentaires dans cette console. C'est une console d'administration qui se veut plutôt pour les développeurs que l'exploitation mais elle va offrir un certain nombre de fonctionnalités pour pouvoir voir notamment tout ce qui est documentation. Dès qu'on expose un endpoint dans l'API, il est automatiquement listé dans la console, on voit donc tous les endpoints disponibles et on peut les tester directement, on n'a pas besoin d'utiliser un Postman ou du curl à côté. Et, dans ces tests, on a connaissance de l'API donc on a directement une interface spécifique à l'API, où on n'a plus qu'à remplir les paramètres tels qu'ils sont attendus.
On a aussi dans cette console un petit peu de monitoring, pour les performances, puisque ça reste un focus toujours important pour moi. On a aussi des exemples de code, effectivement sur la partie tests il y a tout un mécanisme qui permet de faire du test d'intégration avec RESTX. Ce sont des tests qui vont démarrer un serveur RESTX complet et l'attaquer en HTTP pour vérifier que les choses marchent. Là-dessus en fait on va spécifier le comportement qu'on voudrait avoir dans son serveur, avec des spécifications écrites sous forme de requête HTTP + le résultat attendu, dans un fichier de description en YAML. A partir de ça RESTX va être capable de charger la spécification et de l'utiliser comme jeu de test d'intégration. Et il va s'en servir pour d'autres choses encore...
InfoQ : D'accord... Quels autres usages des fichiers de spécification concrètement ?
Xavier : Eh bien en fait, ces fichiers-là qui sont vraiment descriptifs, il va s'en servir pour alimenter des exemples dans la partie documentation. Dans une documentation, ce que j'apprécie le plus, en plus d'avoir des commentaires, c'est surtout d'avoir des exemples de comment je pourrais utiliser l'API, et là ça donne des exemples concrets directement. Et l'autre avantage c'est que ce sont des exemples qui fonctionnent forcément puisqu'ils servent aussi de tests. Et un dernier usage qui est possible avec ça, c'est qu'on peut se servir de ces spécifications pour faire tourner un serveur qui fait du mock HTTP. Donc si on n'a pas encore écrit complètement son serveur, qu'on a une équipe qui travaille sur le client et qui doit attaquer ce serveur, on peut commencer par spécifier ce qu'il devrait faire et on va pouvoir faire tourner ce serveur de mock qui va répondre aux requêtes HTTP qu'il reconnaît dans les specs par la réponse définie dans celles-ci. Ça va permettre d'avancer à des vitesses un petit peu différentes entre la partie cliente et la partie serveur, et pour autant lorsqu'on débouchonne ça se passe bien puisque ça sert de test d'un côté et de mock de l'autre.
InfoQ : Effectivement une vraie synergie entre les parties spec, test et documentation.
Xavier : Oui, c'était un point important, une idée sur laquelle je voulais beaucoup travailler, et que la partie REST permet vraiment de faire puisque le côté stateless d'une architecture REST c'est ça qui permet d'isoler chacune des requêtes qui sont auto-suffisantes et spécifiables comme ça séparément.
InfoQ : Alors aujourd'hui dans les systèmes d'information qui sont ouverts sur l'extérieur, il y a un point qui est essentiel c'est la sécurité. Comment est-ce qu'on peut sécuriser ses webservices avec RESTX ?
Xavier : Eh bien, il y a un choix qui a été fait dans RESTX qui est de dire que justement la sécurité est un focus important, et du coup le principe, c'est que les webservices RESTX sont sécurisés par défaut. C'est quand on veut pouvoir les exposer de façon publique qu'il va falloir le spécifier avec une annotation, mais sinon on aura quelque chose qui est sécurisé par défaut. Alors sécurisé ça veux dire quoi ? Ca veux dire simplement que RESTX va vérifier qu'on est authentifié avant de pouvoir répondre sur l'ensemble des endpoints qui sont offerts. Le fait d'être authentifié, ça par contre, ça reste complètement libre à l'application de définir comment. RESTX vient dans un des plugins avec un mécanisme de gestion de l'authentification finalement assez simple et classique à utiliser où on va pouvoir chercher ses utilisateurs dans n'importe quel repository. Mais on peut tout à fait utiliser n'importe quel autre mécanisme d'authentification, c'est complètement pluggable et on peut même, si on est dans un conteneur de Servlet, utiliser la sécurité de celui-ci. Le point à retenir c'est vraiment que par défaut on est sécurisé, on ne peut pas oublier de demander une authentification.
InfoQ : Donc en fait il y a un service en charge de cette vérification, sur lequel on se plug pour l'étendre ?
Xavier : Tout à fait. En fait, il y a une méthode d'une interface qui va être appelée à chaque fois quand on rentre sur les endpoints avant d'appeler la méthode de l'application elle-même. Et c'est cet élément-là qui est pluggable, donc on peut vraiment faire ce qu'on veut à ce niveau-là pour l'implémentation qu'on souhaite.
InfoQ : J'ai cru comprendre qu'il y avait aussi un système d'injection de dépendance dans RESTX qui a été fait maison. J'imagine aussi dans un soucis d'intégration et de performance ?
Xavier : Oui, alors ça c'était pas prévu à la base, je n'avais pas prévu de refaire un nième moteur d'injection de dépendance. Mais en fait, confronté aux problématiques de vouloir toujours utiliser au minimum l'API Reflection, je n'ai pas vraiment trouvé de moteur d'injection de dépendance qui ne passe pas par cette API. J'en ai trouvé un, c'est Dagger, c'est fait par les gens de Square (ils sont brillants et ont fait quelque chose de très très bien avec Dagger), mais son orientation c'est plutôt un moteur d'injection de dépendance avec une cible notamment pour Android. Donc beaucoup d'efficacité, comme moi, mais plutôt avec une cible mobile. Au début, j'ai commencé à l'utiliser mais il y a eu un point que je n'ai pas réussi à faire avec Dagger, c'est le côté découverte de plugins. Moi je voulais vraiment pouvoir découvrir des plugins disponibles, donc quand je dis "il n'y a pas de classpath-scanning" c'est presque pas en fait. Il y en a un tout petit peu puisque j'utilise l'API ServiceLoader de Java 6 qui en fait un tout petit peu, mais est très rapide puisqu'il cherche juste un fichier particulier dans chacun des jars du classpath, on va dire. Et du coup, c'est très efficace et là, il va faire des instanciations par l'API Reflection, mais il en fait très très peu, les composants eux-même ne sont pas instanciés par le ServiceLoader, c'est juste des fabriques.
Donc j'ai voulu avoir ça, et je me suis dit "ça n'est pas très compliqué à réécrire" et j'ai fait un petit moteur d'injection de dépendance, qui a l'avantage d'être extrêmement performant puisqu'il est basé sur du code généré par annotation processing, et puis d'être type-safe car il génère du code qui doit compiler.
InfoQ : Est-ce qu'il y a eu une intégration particulière avec les différents IDE, pour tout ce qui est annotation-processing, etc... ?
Xavier : Là-dessus en fait l'annotation-processing c'est du standard Java, c'est directement disponible dans javac, dans la compilation, depuis Java 6. Avec javac il suffit que le jar qui définit les annotation processors soit dans le classpath et ça suffit pour que javac fasse sa compilation. Du coup, il n'y a pas besoin de grand chose dans l'IDE si ce n'est qu'il utilise javac correctement... Il y a juste des petits gotcha par rapport à Eclipse puisque dans Eclipse ça n'est pas le compilateur standard de Java qui est utilisé, c'est celui de JDT, qui a une implémentation sur l'annotation-processing qui est un petit peu différente, et donc j'ai travaillé pour que ça fonctionne bien sur les deux. J'ai eu récemment des retours qui m'indiquaient que dans certains cas il y a encore des petits problèmes, et je travaille à les corriger. Mais globalement il y a de la documentation qui indique comment paramétrer son IDE, même si, de base en général, ils le font comme il faut. Il faut juste vérifier. Si on utilise Maven pour le build par exemple, on peut vérifier l'intégration correcte entre les différents éléments, et il y a de la documentation sur le site pour ça...
InfoQ : Est-ce que tu as des points particuliers à mettre en avant, comme par exemple un petit module à présenter, ou bien une roadmap pour les prochaines versions ?
Xavier : En termes de modules, il y en a un assez intéressant sur la partie persistance. C'est un module pour accéder à une base MongoDB, puisqu'en fait ce projet-là a été créé dans le cadre initialement d'un projet sur lequel on faisait de la persistance avec MongoDB. Du coup, il y a un module qui intègre directement une librairie opensource développée principalement en France qui s'appelle Jongo, qui est d'excellente qualité, avec un design qui m'a vraiment beaucoup plu. L'avantage de cette librairie-là c'est qu'elle va, pour faire le mapping des objets Java en tant que documents dans la base MongoDB, utiliser un outil de mapping JSon, en l'occurence par défaut Jackson. Et ils vont faire ce mapping non pas vers du JSon mais directement vers du BSon, le format MongoDB dérivé simplement de JSon mais un petit peu plus efficace. Ils font ce mapping directement avec ça et c'est aussi Jackson l'outil utilisé dans RESTX pour faire le mapping JSon des requêtes HTTP. L'avantage de ça c'est qu'on ne va décrire son mapping qu'une seule fois, et du coup mapper des représentations de ressources arrivant en JSon vers des objets Java avec Jackson (paramétré par annotations) et derrière re-mapper ça dans la base MongoDB avec Jongo. Et pour les cas simples, il n'y aura vraiment rien à faire. Pour les cas compliqués, il y a un support de vues avec Jackson qui permet de définir des représentations différentes. Et RESTX vient avec des vues pour le client et pour la base, donc on peut avoir des éléments qu'on ne va mapper qu'en base de données et ne pas mapper sur l'API REST, ou au contraire des choses qu'on veut avoir simplement dans l'API REST mais pas stocker.
Ça, c'est supporté par défaut dans RESTX, et ça va plus loin parce qu'il y a une fonctionnalité dont je n'ai pas parlé lorsque j'ai abordé la partie test. Les spécifications dont j'ai parlé tout à l'heure en fait on peut les enregistrer lorsque l'on joue avec l'API, avec la console si à un moment donné on se dit "tiens, là ça fait ce que je veux", on peut enregistrer cette requête là et sa réponse. Et donc on va aussi enregistrer l'état du système au moment où on exécute cette requête. Par exemple si on dit "je veux récupérer une liste de personnes", eh bien en fait cette liste de personnes elle est en base de données. Donc pour que le système puisse répondre cette liste de personnes quand je fais le test, il faut que la base de données ait ça à l'intérieur. Et là, avec Jongo, on va détecter et capturer les collections Mongo qui sont utilisées lors de l'appel à cette ressource, pour pouvoir lors des tests démarrer une instance de base dédiée aux tests, alimentée avec ces collections-là, pour pouvoir exécuter le test et vérifier les choses derrière. Tout ça vraiment en appuyant sur un bouton "Record" si on utilise ce module Jongo, ce qui est vraiment un gros avantage en termes de productivité sur des tests qui sont plutôt là des tests de non-régression (du "test after" plutôt que du "test first"). Mais je pense que c'est quelque chose qui, je pense, reste assez intéressant.
En termes de RoadMap, pour l'instant, on est en version 0.2.9.1 qui est sortie mardi (NdR : une version 0.2.9.2 est sortie depuis, le 26 septembre 2013). On est donc sur des versions 0.x pour l'instant, et la cible c'est de sortir une version 1.0 début 2014. La version actuelle est déjà très stable, et même utilisée en production sur certains projets (même si ce n'est pas un projet développé sur le compte d'un projet client, c'est vraiment un projet opensource que je fais le soir à côté). Mais c'est plus la stabilisation de l'API que je voudrais faire avant d'arriver en 1.0, parce que pour moi c'est assez important une fois qu'on marque la 1.0 de garder la backward-compatibility à long terme. D'ailleurs, je l'ai montré avec Ivy. Ceux qui ont écrit des ivy.xml en début 2004 avec la première version d'Ivy qui est sortie en 1.0 en avril 2004, eh bien ils peuvent reprendre leurs ivy.xml écrits en 2004 et les utiliser avec la dernière version en date, Ivy 2.3.0. Donc ça c'est quelque chose que je garde vraiment à l'esprit. Les annotations sont assez stables, mais il y a aussi une possibilité dont on n'a pas parlé, qui est de ne pas passer par les annotations mais d'écrire des routes directement programmatiquement. Et là, on a une API un peu plus bas niveau, qui est proche de l'API Servlet mais avec des choses vraiment orientées REST, et de ce côté-là, il y a encore des stabilisations de l'API à faire... Avec d'autres idées d'améliorations et des bugfix, etc...
InfoQ : Merci Xavier d'avoir présenté RESTX. A bientôt !
Xavier : Merci de m'avoir écouté :) A bientôt.