WebServices / SOAP

Les spécifications WebService

Simple Object Access Protocol

SOAP (Simple Object Access Protocol) est un standard développé par le W3C (World Wide Web Consortium). Sa version 1.1 a été publiée en 2000 sous la forme d'une note. Elle n'est pas censée être utilisée, contrairement à la version 1.2 (2003). Cependant, étant donné l'arrivée tardive d'une version finale, les implémentations WebServices n'ont pas eu d'autre choix que d'utiliser la version 1.1, ce qui explique sa forte présence dans ces implémentations et son choix dans le profil basique.

Ce protocole repose entièrement sur le langage de description XML. Son objectif est de définir la structure générale des messages échangés entre les composants WebServices, sans pour autant en définir la structure du contenu. En ce sens, c'est un protocole peu restrictif, qui laisse aux composants WebServices le soin de définir comment ils formateront le contenu du message.
Les messages SOAP n'ont pour vocation d'être utilisés dans un mécanisme requête/réponse. Aussi, même si dans la pratique c'est ce type de mécanisme qui est utilisé entre un client et son fournisseur, les messages SOAP échangés n'auront pas de relation (ce sont des messages « one-way »).

Structure générale

Voici un exemple typique qui décrit la structure d'un message SOAP:

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

  <soap:Header>
  <!-- optionnel -->
  ...
  </soap:Header>

  <soap:Body>
  <!-- requis -->
  ...

    <soap:Fault>
    ...
    </soap:Fault>

  </soap:Body>

</soap:Envelope>

Au delà de la structure XML classique, on y trouve les blocs:

On notera que l'attribut encodingStyle est inclus dans le protocole SOAP v1.1, mais est interdit dans les modifications faites par le profil basique, car il introduit trop de complexité. Ainsi, pour spécifier le typage, c'est l'attribut xsi:type appartenant à la norme XML qu'il faut utiliser dans le bloc Envelope.

Par la suite, nous étudierons plus en détail le contenu des blocs Header, Body et Fault.

Le bloc <header>

Ce bloque contient des éléments fils dont la signification est spécifique à l'application, permettant ainsi l'ajout d'extensions. Ces éléments doivent être désignés en incluant le namespace de l'élément afin de ne pas confondre cet élément avec les éléments SOAP.
SOAP définit cependant des attributs optionnels applicables sur les éléments fils directs du bloc Header. Ces attributs sont:

Voici un exemple de bloc Header:

<soap:Header>
  <m:User xmlns:m="http://www.exemple.com/rights/"
          soap:actor="http://www.exemple.com/rights/RightsManager">
    Charles
  </m:User>

  <m:Session xmlns:m="http://www.exemple.com/session/"
             soap:mustUnderstand="1">12AE3C</m:Session>

  <m:Lang xmlns:m="http://www.exemple.com/lang/"
          soap:actor="http://schemas.xmlsoap.org/soap/next"
          soap:mustUnderstand="0">
    FR
  </m:Lang>

</soap:Header>

Ici, on voit que l'élément User est à destination d'un composant de gestion des droits (RightsManager) et qu'il contient un nom d'utilisateur.
L'élément suivant, Session, est lui à destination du destinataire final du message SOAP. Il indique un numéro de session, et doit absolument être compris par le destinataire pour pouvoir traiter le message.
Enfin, le dernier élément de l'en-tête, Lang est à destination du prochain composant sur le chemin et ne doit pas forcement être compris par ce composant. On notera que l'URL donnée à l'attribut actor pour désigner le prochain composant du chemin n'a normalement pas de signification avec la norme SOAP v1.1, car il s'agit d'une valeur spécifiée dans la norme SOAP v1.2. Elle n'est donnée ici qu'à titre d'exemple.

Il est important de rappeler que les éléments User, Session, et Lang ne sont que des éléments d'exemples et ne font pas partie de la norme SOAP.

Le bloc <body>

Ce bloc contient le corps du message. Sa signification est spécifique à l'application.
On peut cependant imaginer un exemple de deux contenus de blocs Body (venant de deux messages SOAP différents donc), le premier formulant une requête pour obtenir le prix d'une pomme:

<!-- exemple de demande -->
<soap:Body>
   <m:GetPrice xmlns:m="http://www.exemple.com/prices">
      <m:Item>Pomme</m:Item>
   </m:GetPrice>
</soap:Body>

Et le second représentant la "réponse" à cette requête:

<!-- exemple de réponse -->
<soap:Body>
   <m:GetPriceResponse xmlns:m="http://www.exemple.com/prices">
      <m:Price>1.90</m:Price>
   </m:GetPriceResponse>
</soap:Body>

On peut clairement voir ici l'aspect peu restrictif de SOAP étant donné que le contenu propre du message ne dépend pas de SOAP. Il n'est cependant pas nécessaire qu'un client et un fournisseur connaissent à l'avance ce qu'il faudra mettre dans le corps du message, une phase découverte dynamique du contenu à inclure dans le message pouvant être effectuer avec un protocole tel WSDL.

Le bloc <fault>

Le bloc Fault est le seul bloc définit pouvant être contenu dans le bloc Body. Il y est présent uniquement en cas d'erreur afin de remonter l'erreur à l'émetteur du message SOAP.
Ce bloc doit contenir 4 éléments:

Exemple d'un bloc Fault:

<soap:Body>
  <soap:Fault>
    <faultcode>soap:Server</faultcode>
    <faultstring>Impossible de router le message.</faultstring>
    <faultactor>http://www.exemple.com/messageDispatcher</faultactor>
    <detail>
      <m:error xmlns:m="http://www.exemple.com/errors">
        E_NO_ROUTE
      </m:error>
    </detail>
  </soap:Fault>
</soap:Body>

Ici, l'erreur provient d'un composant de répartition des messages (messageDispatcher) qui n'a pas été en mesure de traiter le message (i.e., de le diriger vers le destinataire final). On constate le passage d'informations spécifiques à l'application dans l'élément detail.