Les Web Services...

Un WebService (ou service Web selon les envies) représente une collection de fonctionnalités mises à disposition à travers les protocoles de l'Internet. Cela permet de sortir du carcan de la programmation monolithique réalisée par une seule personne - physique ou société - en autorisant l'interopérabilité avec d'autres langages et applications.

Il est fréquent de voir fleurir des applications permettant l'affichage de la météo à partir d'un site de référence autorisant l'interrogation de ses services gratuitement par exemple. Il existe en fait une quantité très large de webservices pour tous types d'usages.

Il n'est cependant pas évident de mettre tous ces éléments en place afin d'obtenir une chaîne de programmes qui fonctionnent car les règles à respecter sont assez strictes et parfois mal documentées (avec beaucoup de documents obscurs i.e. MSDN). C'est la raison pour laquelle cette page va essayer de rendre plus clairs la création et l'usage des services Web.

Les Web Services reposent sur un principe d'échanges de messages au format XML et utilisant le protocole HTTP comme protocole de transport de l'information. Les services Web peuvent être classés selon deux typologies :

  • SOAP (Simple Object Access Protocol) est un véritable protocole de communication avec des serivces mis en place sur des serveurs distants pouvant exposer un ensemble arbitraire de fonctions. Ces fonctions sont connues par la mise à disposition d'un catalogue de fonctions au format WSDL (Web Services Description Language) et regroupant l'ensemble des éléments permettant d'accéder aux web services (méthodes, paramètres d'appel, paramètres de retour, ports utilisés, formats d'échange...). Cela permet de qualifier SOAP comme support pour une intégration globale de services distants pouvant aller de la gestion d'un ERP à la simple récupération de la météorologie locale.
  • REST (REpresentational State Transfer) est une méthode d'échange de ressources web également basée sur le XML mais généralement orientée vers une interrogation d'éléments plus simples qu'un logiciel d'entreprise. Le transport HTTP n'emprunte que 4 méthodes du protocole HTTP : POST, PUT, GET et DELETE. Cela permet aux applications de dialoguer entre-elles en s'échangeant des messages ou des objets dans un format connu. Généralement limité à la manipulation dans un environnement CRUD (Create, Read, Update, Delete). On destinera REST plutôt à la mise à jour d'informations typiquement Web (page web).
Pour simplifier nous pourrions dire que REST ne concerne que la partie des services utilisés à travers des navigateurs internet, alors que SOAP permet une intégration plus importante avec les serveurs applicatifs du type CRM ou applications métiers spécifiques. REST est donc un sous-ensemble de SOAP globalement.

Pour ma part je ne parlerai que de la version SOAP des WebServices, ce qui permettra de réaliser l'ensemble de ce que l'on souhaite obtenir avec un service Web. Le cadre suivi sera de réaliser le service Web en PHP (pour faire tourner le service sur n'importe quel site hébergé et pas seulement sur un VPS ou une machine louée à la Windows) et de proposer différents clients qui vont consommer ce service : un client PHP, un client python, un client en pur C, un autre en Java ainsi qu'un dernier réalisé avec le Framework .NET (oui tout de même). D'autres sont probablement à venir pour essayer d'avoir une vision la plus exhaustive possible...

Comment fonctionne un Web Service ?

Dans l'idée, le client qui veut consommer un Web Service va commencer par interroger la page Web afin de déterminer quelles sont les opérations qui sont mises à sa disposition. Ce sont les services exportés par le Web Service et avec lesquels il va être possible d'interagir. Une fois ces opérations récupérées, il ne reste plus qu'à lancer l'appel à ces méthodes afin de réceptionner le résultat que l'on espère... Les méthodes exposées par le web service sont regroupées au sein de fichiers de description au format WSDL dont nous verrons plus loin la composition.

Différences SOAP / REST

Comme évoqué précédemment, l'objectif des deux technologies est le même : apporter une mise à jour, supprimer des éléments, faire des recherches... La méthode employée pour réaliser ces opérations diffère quelque peu au niveau des besoins et de la syntaxe à employer.

Prenons l'exemple d'une société qui souhaite pouvoir autoriser les actions suivantes :

  • obtenir la liste des produits
  • mettre à jour un produit
  • créer une commande
  • supprimer une commande
Le tableau ci-après affiche les différences entre les deux modes d'appel REST et SOAP. Rappelez-vous que REST est censé être plus simpliste dans ses possibilités (Create,Read,Update,Delete).
RESTSOAP
GET(URI)listeProduits()
PUT(URI, ressource)MAJProduit(produits)
POST(URI, ressource)creerCommande(commande)
DELETE(URI)supprimerCommande(idCommande)

La différence entre les deux apparaît clairement sur le type de requête à utiliser pour dialoguer avec le web service. Alors que REST n'emploie que les 4 commandes HTTP, SOAPpermet l'usage de commandes similaires à celles utilisées dans les langages de haut niveau.

Disponibilité d'un web service

L'objectif d'un web service est double : rapidité de fonctionnement et interopérabilité entre les divers langages de programmation. L'intérêt d'un web service est généralement de faire exécuter à un serveur distant une requête simple, qui ne monopolise pas de manière exclusive le serveur ayant la charge de l'exécution de cette requête, et qui ne charge pas le réseau de manière inconsidérée.

Les web services sont généralement organisés selon 4 axes :

  • Network - afin de pouvoir être utilisés, les services web doivent être mis en place sur un ou plusieurs serveurs, qui vont se charger de les rendre disponibles.
  • Discovery - un service web qui n'est pas accessible ne sert à rien. Il faut donc le publier sur des annuaires internationaux au format UDDI (Universal Description Discovery Intégration), un mélange entre SOAP et WSDL.
  • Packaging - le fichier WSDL constitue le format de packaging d'un web service. Il expose les fonctions et méthodes utilisables à travers ce web service.
  • Transport - l'échange d'information entre le client et le web service s'effectue généralement par le biais du protocole HTTP, un protocole employé par les navigateurs Web.

Composition d'un fichier WSDL

Un fichier WSDL constitue l'épine dorsale du contrat que va offrir le service web à son client. Ce contrat est technique, et permet à l'application de connaître la manière d'invoquer le service. En aucun cas il n'y a d'information concernant une éventuelle tarification ou la mise en place d'une plaquette commerciale.

Un fichier WSDL est décrit selon une grammaire stricte reposant sur le format XML. Celle-ci sera décrite directement dans le code qui se situe plus loin dans le document.

Un serveur en PHP

J'ai décidé de mettre en place un service web à base de PHP pour une raison simple : la majorité des serveurs web reposent sur le paradigme Apache + Php + MySQL et représentent le plus faible investissement pour cette réalisation. Une autre raison pourrait être de ne pas m'imposer une architecture hyper propriétaire telle que celle de Microsoft et de son langage C# pour cette réalisation. Il aurait alors fallu mettre en place un hébergement sur une plateforme Windows (licence onéreuse) et mettre en place un hébergement Web reposant sur ASP + IIS. C'est moins immédiat et représente trop de contraintes pour un simple Web Service (même pour un Web service complexe... ;-) )

Il existe de nombreuses façons de mettre en place un serveur SOAP en PHP. Nous allons commencer par utiliser ce qui est normalement inclus d'origine avec tous les serveurs Web : la bibliothèque PHP-SOAP. Si vous ne savez pas si votre environnement PHP a été compilé avec le support de SOAP, créez simplement un fichier contenant <?php phpinfo(); ?>, enregistrez-le sur votre serveur sous le nom phpinfo.php (par exemple, mais tout autre nom fera l'affaire) et pointez votre navigateur internet vers ce fichier. Vous devriez obtenir ceci :

Sinon jetez un oeil dans le fichier php.ini de votre installation et décommentez la ligne extension=php_soap.dll. Le fichier php.ini est probablement dans un sous répertoire de /etc/php/<version>. Et en regardant un peu plus bas dans le document, vous pouvez obtenir plus de détail si l'extension SOAP a bien été compilée avec PHP :
Si vous n'avez pas cette bibliothèque, penchez-vous sur la bibliothèque nuSOAP qui vous explique comment utiliser une bibliothèque externe qui s'appelle NuSOAP. Bien que son développement ne soit plus actif, elle vous rendra probablement service...

Avec notre service Web, nous n'allons faire que des choses simples : dire "Bonjour", additionner et soustraire deux nombres. Je sais que vous allez me dire qu'il aurait été plus judicieux de ne pas faire un exemple bateau mais proposer une interaction avec une base de données par exemple... Certes, mais on est ici pour comprendre le mécanisme du Web Service, pas pour développer une application globale non ? Je vous donne le code complet et les commentaires ensuite. Nous supposerons que le fichier du serveur s'appellera srvmath.php


<?php
/*
 * L'utilisation d'une classe pour encapsuler l'ensemble des fonctions mises à disposition
 * par le webservice est préférable à l'utilisation de fonctions dans le corps du fichier car Cela
 * permet d'éviter l'usage trop important de $server->addFunction()
 */
class Math
{
  public function Add($a, $b) {
  return $a + $b;
  }
	
  public function Subtract($a, $b) {
    return $a - $b;
  }
	
  public function Bonjour($qui) {
    return "Bonjour $qui";
  }
}

// Désactiver le cache WSDL lors de la phase de test
ini_set("soap.wsdl_cache_enabled", "0");

$server = new SoapServer(null,
   array('uri' => 'http://<serveur>:<port>/srvmath.php'));

// Ajout de la classe Math dans les éléments proposés par le WebService
$server->setClass('Math');
$server->handle();
?>
	

Maintenant que nous avons le serveur en place, qui jouera le rôle de WebService, nous allons écrire un client qui va interroger ce serveur et afficher les informations renvoyées. Il s'appellera clientMath.php.'


<?php

ini_set("soap.wsdl_cache_enabled", "0");
$client = new SoapClient("http://<serveur>:<port>/srvmath.wsdl");
$ret = $client->Add(5, 7);
echo '5 + 7 = ' . $ret;
echo '<br />';

$ret = $client->Subtract(5, 7);
echo '5 - 7 = ' . $ret;
echo '<br />';

$ret = $client->Bonjour("Maître");
echo $ret;
?>
	
Créer un fichier WSDL

Pour permettre une bonne détection des différentes fonctions exportées par le serveur SOAP, il est recommandé (fortement même) de définir un fichier de description au format WSDL. C'est un peu compliqué à décrire, même si le format respecte le XML... Je vous livre le fichier dans son intégralité avec les commentaires pour les explications.


/*
 * On commence par définir la version du format XML employé ainsi que l'éventuel encodage
 * des caractères du document WSDL. Ce sera actuellement toujours le format 1.0 du langage
 * XML qui sera utilisé.
 */
<?xml version='1.0' encoding='utf-8' ?>

/*
 * L'élément racine du document se nomme definitions. Ce namespace donne le nom réel du
 * service et peut prendre de nombreux attributs.
 * Dans notre exemple, le webservice portera le nom de 'srvmath'.
 */
<definitions name='srvmath'
/*
* Création d'une section constituant la racine du document XML.
* Cette racine porte le nom 'srvmath' qui est en fait le nom qui va définir le service web.
* Des attributs supplémentaires sont présents, pas obligatoires mais constituant la liste
* des formats d'encodage de chaque rubrique.
* Je vous conseille de ne modifier que les 3 premiers avec le nom de votre service uniquement.
*/
  targetNamespace='srvmath'
  xmlns:tns='srvmath'
  xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
  xmlns:xsd='http://www.w3.org/2001/XMLSchema'
  xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding'
  xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
  xmlns='http://schemas.xmlsoap.org/wsdl/'>

/*
* La section des messages constitue les informations transmises sur les files d'attente des
* services web. Ces files sont toujours au nombre de deux : une pour l'envoi (Request) et l'autre pour
* la réception des informations (Response).
* La fonction 'Add' du service web attend en entrée (Request) deux variables de
* type flottant, nommées 'a' et 'b'. La fonction retourne une valeur flottante nommée
* 'result' sur la file de message 'Response'.
* Même chose pour la fonction Subtract().
*/
<message name='AddRequest'>
  <part name='a' type='xsd:float' />
  <part name='b' type='xsd:float' />
</message>
<message name='AddResponse'>
  <part name='result' type='xsd:float' />
</message>
<message name='SubtractRequest'>
  <part name='a' type='xsd:float' />
  <part name='b' type='xsd:float' />
</message>
<message name='SubtractResponse'>
  <part name='result' type='xsd:float' />
</message>

/*
* Même chose pour la méthode 'Bonjour' qui déclare deux files de messages : une pour les
* paramètres en entrée, l'autre pour les valeurs de retour. Ici ce sont à chaque fois une
* valeur en paramètre d'entrée de type string et une valeur de retour de méthode qui est
* également de type string.
*/
<message name='BonjourRequest'>
  <part name='qui' type='xsd:string' />
</message>
<message name='BonjourResponse'>
  <part name='result' type='xsd:string' />
</message>

/*
* La section portType définit la connexion avec les différentes files de messages pour
* chaque sens de communication sur les opérations. Un portType associe des files de messages
* entrants et sortants.
* Nous avons ici un type nommé 'srvmathPortType' disposant de trois méthodes 'Add', 'Subtract' et 'Bonjour'.
* Ces méthodes définissent des files de messages input et output avec les noms logiques associés.
* Un port est donc une suite d'opérations que l'on pourrait qualifier de bibliothèque ou de module ou 
* même de classe.
*/
<portType name='srvmathPortType'>
  <operation name='Add'>
    <input message='tns:AddRequest' />
    <output message='tns:AddResponse' />
  </operation>
  <operation name='Subtract'>
    <input message='tns:SubtractRequest' />
    <output message='tns:SubtractResponse' />
  </operation>
  <operation name='Bonjour'>
    <input message='tns:BonjourRequest' />
    <output message='tns:BonjourResponse' />
  </operation>
</portType>

/*
* La section binding décrit comment le webservice sera implémenté et la façon dont les messages
* seront transmis.
* Nous allons donc rattacher le port à SOAP, tout en sachant que les ports sont indépendants
* du protocole SOAP.
* Nous allons utiliser des requêtes SOAP (soap:binding) de type RPC (style='rpc') via du transport
* HTTP (transport='http://schemas.xmlsoap.org/soap/http') avec un encodage SOAP
* (encodingStyle='http://schemas.xmlsoap.org/soap/encoding/')
*/
<binding name='srvmathBinding' type='srvmathPortType'>
  <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http' />
  <operation name='Add'>
    <soap:operation soapAction='urn:xmethods-delayed-quotes#Add' />
    <input>
      <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' />
    </input>
    <output>
      <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' />
    </output>
  </operation>
  <operation name='Subtract'>
    <soap:operation soapAction='urn:xmethods-delayed-quotes#Subtract' />
    <input>
  <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' />
    </input>
    <output>
      <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' />
    </output>
  </operation>
  <operation name='Bonjour'>
    <soap:operation soapAction='urn:xmethods-delayed-quotes#Bonjour' />
    <input>
      <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' />
    </input>
    <output>
      <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' />
    </output>
  </operation>
</binding>

/*
* La section service constitue le nom du service à invoquer ainsi que les ports utilisés.
* Un service est généralement composé d'une simple URL.
*/
<service name='srvmathService'>
  <documentation>Des opérations et un message...</documentation>
  <port name='srvmathPort' binding='srvmathBinding'>
    <soap:address location='http://<serveur>:<port>/srvmath.php' />
  </port>
</service>

</definitions>
      
Consommer un service Web

Si vous avez suivi l'exemple ci-dessus, vous avez déjà pu avoir un aperçu de la façon dont peut se consommer un service Web via PHP. Nous allons voir différentes approches avec différents langages pour essayer de vraiment faire le tour de la question.

Avec Java

Avec Python

Avec Python

Avec le langage C

© LGB - 201x+