$ curl -L cpanmin.us | perl - Mojolicious --local-lib=/var/www/testmojo/mojolicious/
curl se connecte à cpanmin.us (ouvrez la page dans votre navigateur, ça pointe vers un module Perl hébergé sur github), récupère App::cpanminus et le fait exécuter par perl pour installer Mojolicious.
L'option //--local-lib// permet d'installer Mojolicious dans un répertoire choisit par l'utilisateur. Vous pouvez également lancer cette commande sans spécifier de //local lib//, auquel cas il vous faudra être root et Mojolicious s'installera dans les répertoires du système.
julien@arael:/var/www/testmojo$ mv mojolicious/lib/perl5/ lib
$ tree lib/ -L 1
lib/
|--- CPAN
|--- ExtUtils
|--- inc
|--- Module
|--- Mojo
|--- Mojolicious
|--- Mojolicious.pm
|--- Mojo.pm
|--- ojo.pm
|--- Perl
|--- README.pod
|--- Test
`--- x86_64-linux-gnu-thread-multi
Il ne restera plus qu'à inclure ce répertoire 'lib' dans le code de la webapp.
La page de manuel de Mojolicious::Lite présente un exemple de "Hello World!" avec lequel nous allons démarrer.
$ man ./mojolicious/man/man3/Mojolicious::Lite.3pm
NAME
Mojolicious::Lite - Micro Web Framework
[...]
Hello World!
A minimal Hello World application looks like this, strict and warnings are automatically enabled and a few functions imported when you use Mojolicious::Lite, turning your script into a full featured web application.
#!/usr/bin/env perl
use Mojolicious::Lite;
get '/' => sub { shift->render(text => 'Hello World!') };
app->start;
[...]
Le code ci-dessus utilise le module Mojolicious::Lite, une version simplifiée du framework, et démarre une application qui renvoie le texte 'Hello World!' dès qu'un client effectue un GET sur la page '/'.
==== 1.1 Exécuter le code ====
Par habitude, mon premier réflexe en découvrant Mojolicious a été de monter un serveur Nginx avec FastCGI via spawn-fcgi et fcgiwrap, ma configuration habituelle pour exécuter du Perl/CGI. Mais ce n'est pas idéal. Le problème de cette configuration, c'est sa lenteur. Dans ma configuration de test, fcgiwrap ne parvenait pas à répondre a plus de 2,5 requêtes par secondes (sur un petit processeur, je vous l'accorde).
Hors, Mojolicious embarque toute une couche de communication, incluant les protocoles de transport que sont HTTP, CGI/FastCGI/PSGI et également un support des WebSockets. De fait, un programme utilisant Mojolicious peut directement lancer son propre serveur web (on verra plus tard comment contrôler cela avec Hypnotoad).
$ perl hello.pl daemon --reload
Sat Feb 26 15:14:45 2011 info Mojo::Server::Daemon:320 [7792]: Server listening (http://*:3000)
Server available at http://*:3000.
Et dirigez-vous vers http://localhost:3000/ pour admirer votre Hello World.
L'option **--reload** indique à Mojolicious de recharger automatiquement le code lorsqu'il est modifié. Ainsi, si vous changez "Hello World!" par "Bonjour Jean-Kevin..." et sauvegardez, le changement sera pris en compte sans relance du serveur.
Vous noterez également que la console dans laquelle le serveur est lancée affiche les logs de chaque requête. Pratique pour débugguer.
===== 2. Modèle en couche =====
On l'a dit, Mojolicious est composée de plusieurs couches communiquant entre elles. La couche la plus basse est celle du transport, où l'on retrouve les protocoles réseaux. Ensuite vient Mojo. Mojo est le moteur de Mojolicious, il a été initialement écrit par Sebastian Riedel en 2008 pour améliorer Catalyst. Devant la réticence des mainteneurs de Catalyst à intégrer Mojo, Sebastian à écrit Mojolicious comme exemple d'utilisation, ne prévoyant alors pas que ce dernier grandirait au point de devenir un framework à part entière.
Puis vient Mojolicious::Lite comme couche d'abstraction à Mojolicious. Toutefois, Mojolicious::Lite est entièrement basé sur Mojolicious et passer du framework allégé à la version complète n'implique pas de ré-écriture.
URL : <%= text_field 'orig_url' %> <%= submit_button 'Raccourcir' %>
<% end %>
$ perl shorturl.pl daemon --reload
Sat Feb 26 16:35:46 2011 info Mojo::Server::Daemon:316 [9325]: Server listening (http://*:3000)
Server available at http://*:3000.
==== 3.1 Ajouter la route du Post ====
Si vous essayez de soumettre une URL dans le formulaire, Mojolicious vous répondra avec le message "Page not found, want to go home?". C'est le comportement par défaut lorsque le framework ne connait pas la route à laquelle vous souhaitez accéder.
Juste après le code de la page d'accueil, et avant 'app->start();', nous allons donc ajouter la déclaration de la route 'sendurl' avec la portion de code qui suit :
Votre adresse a ete enregistree
URL courte : http://<%=$host%>/<%=$shortened%>
URL courte : http://<%=$host%>:<%=$port%>/<%=$shortened%>
$ tree templates/ -L 2
templates/
|--- confirm.html.ep
|--- index.html.ep
`--- layouts
`- default.html.ep
==== 4.2 Packages ====
De même que pour les templates, il est souhaitable de séparer la logique du contrôleur du coeur de l'application. On va donc créer un package **ShortURL.pm** qui va contenir les fonctions //get_url()// et //store_url()//. Ce package est créé dans le répertoire 'lib' de l'application, comme suis:
$ cat production.log
Sat Feb 26 18:53:20 2011 error Mojo::Loader:16 [12514]: appel de la page d'accueil
Toutefois, si cette information n'est pas intéressante en production, on peut simplement utiliser le niveau de log debug:
$ tail -n 1 production.log
Sat Feb 26 19:13:30 2011 error Mojo::Loader:25 [12514]: Requete recue => GET / HTTP/1.1 depuis 127.0.0.1
===== 6. Définir un fichier de configuration =====
Jusqu'ici, nous avons conservé certaines valeurs en dur dans le code. Hors, Mojolicious permet de maintenir un fichier de configuration au format JSON, et de lire ce fichier de configuration au démarrage de l'application, ou dans un package. Les paramètres de configuration seront ensuite accessibles dans une structure en mémoire (le //Stash// de l'application).
Lors de la phase de découpage, nous avons créé un package ShortURL contenant le corps de l'application. C'est dans ce package que nous allons lire le fichier de configuration. Mojolicious fournit un plugin du nom de 'json_config'. Par défaut, ce dernier essayera de lire un fichier de configuration à la racine portant le même nom que l'application (dans notre cas, "shorturl.json"). Définissons l'emplacement du stockage des URLs dans ce fichier:
$ vim shorturl.json
{
"storage_file" : "urls.txt"
}
Maintenant, dans lib/ShortURL.pm, il est possible de remplacer les occurences de "urls.txt" dans les fonctions //get_url// et //store_url// par la valeur prise dans le fichier de configuration:
$ perl shorturl.pl test
Running tests from '/var/www/testmojo/t'.
t/shorturl.t .. ok
All tests successful.
Files=1, Tests=3, 1 wallclock secs ( 0.02 usr 0.01 sys + 0.24 cusr 0.03 csys = 0.30 CPU)
Result: PASS
On pourrait également ajouter un test sur l'envoi d'URL via le formulaire. Ce test ressemblerait alors au code suivant:
URL :
<%= text_field 'orig_url' %>
<%= submit_button 'Raccourcir' %>
$ ./mojolicious/bin/hypnotoad --config hypnotoad.conf shorturl.pl
Server available at http://*:8080.
Server available at http://127.0.0.1:3000.
Par défaut, hypnotoad place son pid dans **hypnotoad.pid** à la racine de l'application.
Une autre fonction intéressante d'hypnotoad est de permettre le rechargement à chaud. Il suffit d'envoyer un signal USR2 au processus hypnotoad et ce dernier va recharger le code, sans se relancer.
$ kill -s 'USR2' `cat hypnotoad.pid`
==== 9.1 Et ça va vite ? ====
Plutôt vite oui ! Sur ma machine de test, un petit Atom D510, Mojolicious répond aux GET avec une moyenne stable de 250 hits par secondes et consomme un peu plus de 12Mo de mémoire résidente par worker. Evidemment, notre application de test est bien trop limitée pour prouver une supériorité par rapport à d'autres framework. Mais pour un début, c'est déjà satisfaisant.
===== 10. Et pour finir =====
Notre balade d'introduction dans le joyeux monde de Mojolicious est terminée, et l'on a seulement survolé les possibilités offertes. Pour aller plus loin, je vous recommande la lecture de la documentation officielle, ainsi que du wiki et de quelques applications (sur github: gadwall - http://1nw.eu/!l0 - et undeadly - http://1nw.eu/!BA). Le code source de notre application est disponible à l'adresse http://1nw.eu/!mojo et si vous voulez une version plus avancée à installer chez vous, recherchez **1nw** sur github.
Ce framework a clairement un bel avenir devant lui, et amène un peu d'air frais dans le monde de Perl. Il n'est pas exempt de défauts (la non ré-utilisation de nombreux modules CPAN fait débat), mais offre un environnement solide, performant et relativement simple pour le développement d'applications web.