Christophe Nowicki

June 1, 2006

PHP REST SQL, Web Services for dummies

Je vous passe l’ensemble de la propagande habituelle sur les Web Services ( l’architecture SOA, Annuaires de services, SOAP, etc…).

Pour ma part, je pense qu’il existe deux grandes familles de WebServices :

  • Contrôle : l’éxécution d’action
  • Données : la mise à disposition d’informations

Pour la première famille, l’ensemble des techniques disponibles (SOAP, WSDL, UDDI) couvrent les besoins.
Quant à la seconde famille, je trouve que ces techniques sont bien trop complexes à mettre en oeuvre.

Problèmatique

Imaginons que vous avez besoin de mettre à disposition le contenu d’une base de données relationnelles ( liste de contacts, tickets, commandes en cours, etc. ) à l’aide d’un Service Web.

1/ Solution envisagée : le développement d’une Interface SOAP spécifique à votre problèmatique

Le développement de celle-ci sera long, car il vous faudra :

  • désigner l’interface
  • développer les composants
  • tester le fonctionnement
  • écrire la documentation

2/ Solution envisagée : adopter la méthodologie REST

J’ai découvert cette méthodologie suite à un article du journal du Net : SOAP, XML-RPC et EST : différences et intérêts

Elle est spécifiée dans le mémoire de Roy Thomas Fielding : Architectural Styles and the Design of Network-based Software Architectures

Ce qui est remarquable dans cette méthodologie, c’est :

  • sa simplicité
  • la réutilisation de protocoles standards éxistants du web
  • la possiblité de mettre en cache le résultat de la requête de manière transparente.

Le project PHP REST SQL

Par la suite, j’ai découvert le projet PHP REST SQL, celui-ci permet de mettre à disposition le contenu d’une base de données MySQL via une interface Web.

Ce projet consiste en une classe, qui s’interface avec une base de données MySQL et qui permet à l’aide de requêtes HTTP de récupèrer les données de la base, créer, modifier et supprimer des champs.

Ma contribution : abstraction par rapport aux bases de données

Actuellement, le projet ne supporte que les bases de type MySQL, j’ai donc réécrit la classe pour prendre en comptes toutes les bases de données supportées par le module PEAR MDB ( MySQL, PostGreSQL, Oracle, Frontbase, Querysim, Interbase/Firebird, MSSQL et SQLite).

J’ai testé son fonctionnement avec 3 bases (MySQL, PostGreSQL et SQLite).

Cette contribution est disponible sur SourceForge : database abstraction (MySQL, Postgres and SQLite Support).

Installation et Configuration

Installer et mettre en oeuvre le classe, il suffit de :
1/ Télécharger la classe :

$ wget 'http://sourceforge.net/tracker/download.php?group_id=126371&atid=705494&file_id=180054&aid=1498241'  -O php_rest_sql.tar.gz

2/ L’extracter dans votre arborescence Web :

tar xzvf php_rest_sql.tar.gz -C /var/www

3/ Editer le fichier de configuration phprestsql.ini.

4/ Editer un fichier .htacces et activer le module rewrite dans Apache.

Et voila !
Vous pouvez accéder au contenu de votre base de données directement à l’aide d’un navigateur.

Il ne vous reste plus qu’à écrire un client pour accéder aux données, à l’aide de la bibilothèque PHP CURL par exemple.

Conclusion

J’ai soumis mon patch à Paul James, l’auteur du projet et proposé l’idée de transformer celui-ci en module Pear. Il faut savoir que l’auteur a développé le project Tonic autour du même concept.

Mais il s’agit d’un veritable framework de développement web et qui par conséquent est beaucoup plus intrusif.

Filed under: Programming — Tags:, , — cscm @ 10:51

January 12, 2006

Gestion des exceptions SOAP en Perl avec les module SOAP::Lite et Error

Après une longue journée de travail, j’ai enfin réussi à faire fonctionner correctement le système de gestion d’exception de SOAP::Lite avec le module Error. Tout d’abord quelques explications.

Système de gestion d’exception

Tout programme en exécution peut être sujet à des erreurs, pour lesquels des stratégies de détection et de réparation sont possibles. Ces erreurs ne sont donc pas des bogues des programmes, mais des conditions particulières, on parle aussi de conditions exceptionnelles ou exceptions dans le déroulement normal d’une partie d’un programme.

Module Perl Error

Le module CPAN Error permet de gérér les exceptions en Perl. Il propose une interface objet semblable à celle disponible dans des langages comme Java ou bien C#. Le module repose sur la fonction die du langage.

SOAP::Lite

Le projet SOAP::Lite permet de prendre en charge l’ensemble des protocoles lier aux Web Services (SOAP, WSDL et UDDI). L’ensemble des fonctionnalitées offertes sont extrèment riches et puissantes. Vous pouvez aussi bien faire un serveur qu’un client en Perl et vous interfacer avec des Service écrit dans de nombreaux autres langages.

Entre la théorie et la pratique …

L’ensemble des interactions sont décrites dans les spécifications des protocoles de Web Services. Mais comme présque toujours en informatique, chaque constructeur, langage ou implémentation apporte son lot de spécificitées.

Dans le cas du langage Perl, les deux principaux sont l’absence :

  • de typage
  • d’un système de gestion d’exception

Le permier problème se controurne à l’aide de la déclaration des type dans un fichier WSDL.
Pour le second, j’ai eu un peu plus de mal avant de trouver la solution.

A propos du code source de SOAP::Lite

Ce n’est vraiment pas un exemple à suivre :

  • très peu de commentaires dans le code
  • seul fichier de 5000 lignes
  • le mode de debug trace n’est pas assez verbeux
  • on se demande souvent si l’auteur du module n’a pas coder sous l’imfluence de certaines drogues

L’anomalie de fonctionnement

Lorsqu’une exception est levée à l’aide de la fonction throw dans un module Perl elle créer un objet pour indiquer des informations sur le contexte de l’erreur. L’objet le plus simple est Error::Simple

sub foo {
   throw Error::Simple( "A simple error");
}

Il est possible de créer vos propres objets en utilisant l’héritage en utilisant l’objet Error comme base.

La framework SOAP::Lite détourne la fonction die et renvoie une exception SOAP qui contiens un objet. La problème est que cela ne fonctionne pas correctement :

 SOAP Fault :
        Fault String : Application error
        Fault Detail :  {
          'Error__Simple' => {
                             '-file' => 'Demo.pm',
                             '-text' => 'A simple error',
                             '-package' => 'Demo',
                             '-line' => '9'
                           }
        };

        Fault Actor  : http://localhost:4242/

Le contenu de Fault Detail n’est pas un objet MAIS une table de HASH.
De plus un message d’erreur du côte du serveur vous indique qu’il y’a visiblement un problème avec la serialisation :

 Use of uninitialized value in sprintf at /usr/share/perl5/SOAP/Lite.pm line 814.
Cannot encode 'namesp1:something' element as 'hash'. Will be encoded as 'map' in  stead

Après quelques heures de tatonnement et de recherche dans le code source de SOAP::Lite, j’ai trouver la source du problème.

Les attributs du module Error contiennent tous un préfixe qui fait échouer la serialization :

$VAR1 =  bless( {
        '-file' => '...',
        '-text' => '...',
        '-package' => '...',
        '-line' => '...'
        }, 'BadError')

La fonction résponsable de ce bug est SOAP::Serializer::encode_hash.
Une expression régulier empeche la serialisation d’un caractère ‘-‘ dans le flux XML.

J’ai donc déciser de supprimer le caractère ‘-‘ dans le nom des attributs à l’aide du boût de code suivant :

sub encode_hash {

my($self, $hash, $name, $type, $attr) = @_;

  while(my ($k, $v) = each (%$hash))
  {
    if ($k =~ m/^-/)
    {
        $k =~ s/^-//;
        $hash->{$k} = $v;
        delete $hash->{'-'.$k};
    }
  }

  if ($self->autotype && grep {!/$SOAP::Constants::ELMASK/o} keys %$hash) {

Et Voilà !

Cela fonctionne enfin correctement :

 SOAP Fault :
        Fault String : Application error
        Fault Detail :  {
                             'detail' => bless ( {
                             '-file' => 'Demo.pm',
                             '-text' => 'A simple error',
                             '-package' => 'Demo',
                             '-line' => '9'
                           }, 'Error::Simple')
        };

        Fault Actor  : http://localhost:4242/

Je vais contacter l’auteur du module pour trouver une solution plus propore ;0)
Mais en attendant celle-ci fonctionne correctement.

Filed under: Programming — Tags:, , — cscm @ 21:20

November 26, 2005

Génération dynamique de fichiers WSDL avec Perl

Dans le cadre de mon travail, je devais rendre accesible via des Web Services un ensemble de modules écrits en Perl.

Pour que les interfaces d’un module soient accessible via SOAP, il faut les décrire à l’aide du langage WSDL.

Le format WSDL est basé sur XML, il est relativement difficile de le comprendre et encore plus de l’écrire à la main.
C’est pour cette raison que la plupart des langages de programmation proposent des outils de géneration automatique.

Le principale problème que l’ont peut rencontrer avec ce genre d’outils est le manque de contrôle.

Pour palier à ce problème, Perl propose une solution remarquable : décrire l’interface à l’aide de commentaires directement dans le code.

Effectivement à l’aide du module Pod::WSDL, il est possible d’extraire les informations nécessaires pour créer le fichier de déscription d’interface.

Par exemple :

=begin WSDL

_IN $bar $string description du paramètre
_RETURN $string
_FAULT Error::Simple Le type d'éxception déclancher en cas d'erreur
_DOC description rapide du fonctionnement de ma fonction

=cut

sub foo ($) {
my $bar = shift;
return $bar;
}

Ensuite, il ne reste plus qu’à charger le module précédant et extraire les informations pour produire le fichier WSDL, à l’aide du bout de code suivant:

use Pod::WSDL;

my $pod = new Pod::WSDL(
source => 'My::Server',
location => 'http://localhost/My/Server',
pretty => 1,
withDocumentation => 1);

print $pod->WSDL;

Celui-ci vous affiche le fichier WSDL, directement sur la sortie standard.

Les fichiers produits par Pod::WSDL sont conformes aux spécifications et fonctionnent parfaitement.
Je les ai testé avec SOAP::Lite et le framework Apache Axis.

Nous avons une jolie solution pour créer des fichiers WSDL directement lors de l’installation de nos modules.

Néanmoins j’ai voulu pousser le concept de génération dynamique un peu plus loin.

Tout simplement parce que mon interface SOAP est séparée des modules qu’elle met à disposition (dans deux paquets différents).

Dans Web Services, il y a la notion de Web. J’ai donc mis à contribution le framework Mason, qui est un outil de template permetant de faire des sites web dynamiques en Perl.

Celui-ci dispose deux fonctionnalités intéressantes :

  • un système de cache ;
  • un système de gestion de page non disponible.

Le système de gestion de page non disponbile, permet de créer des pages web dynamiquement en fonction de l’url demander.

Le fichier dhandler suivant permet de créer dynamiquement un fichier WSDL en fonction du nom du module Perl:

< %once>
use Pod::WSDL;
use strict;
< %once>
< %init>
my $arg = $m->dhandler_arg;
$arg =~ s/\.wsdl//;
my $pod;

eval {
$pod = new Pod::WSDL(
source => $arg,
location => 'http://localhost/soapEndPoint',
pretty => 1,
withDocumentation => 0
);
};
if ($@) {
return 404;
}
$m->out($pod->WSDL);
< /%init>

Par exemple pour récupèrer le fichier WSDL pour le module Test, il suffit d’aller sur l’url : http://localhost/Test.wsdl.

L’opèration de géneration est rélativement rapide, mais dans le cas d’un service fortement solicité, il faut mettre en place un système de cache, comme celui décrit dans la documentation de Mason : DATA CACHING

Voilà

Filed under: Programming — Tags:, , — cscm @ 22:22

Powered by WordPress