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:
- Envelope: c'est lui qui contient le message et ses différentes sous-blocs. Il s'agit du bloc racine XML. Il peut contenir un attribut encodingStyle dont la valeur est une URL vers un fichier de typage XML qui décrira les types applicables au message SOAP.
- Header: c'est un bloc optionnel qui contient des informations d'en-têtes sur le message. Si il est présent, ce bloc doit toujours se trouver avant le bloc Body à l'intérieur du bloc Envelope.
- Body: c'est le bloc qui contient le corps du message. Il doit absolument être présent de manière unique dans chaque message et être contenu dans le bloc Envelope. SOAP ne définit pas comment est structuré le contenu de ce bloc. Cependant, il définit le bloc Fault qui peut s'y trouver.
- Fault: ce bloc est la seule structure définie par SOAP dans le bloc Body. Il sert à reporter des erreurs lors du traitement du message, ou lors de son transport. Il ne peut apparaître qu'une seule fois par message. Sa présence n'est pas obligatoire.
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:
-
actor: cet attribut identifie le destinataire de l'élément fils. En effet, un
message SOAP peut traverser plusieurs composants avant d'atteindre le destinataire final
du message. Aussi, il peut être nécessaire d'adresser des informations aux composants
intermédiaires qui composent le chemin vers le destinataire final. C'est par
l'intermédiaire de cet attribut que cela est rendu possible, en lui donnant comme valeur
une URL qui correspond à ou aux destinataires de l'élément.
En l'absence de cet attribut, l'élément fils est à destination du destinataire final du message SOAP. -
mustUnderstand: cet attribut indique si le destinataire de l'élément doit
absolument comprendre l'élément ou non. Si cet attribut est à 1, alors le destinataire
doit absolument comprendre l'élément. Si ça n'est pas le cas, un message d'erreur
(i.e., contenant un bloc Fault)est retourné.
Si cet attribut est à 0, l'élément peut être ignoré. C'est le comportement par défaut quand l'attribut n'est pas spécifié. - encodingStyle: la signification de cet attribut est la même que pour le bloc Envelope. Sa portée reste cependant limité à l'élément fils. Ici encore, cet attribut n'est pas permis par le profil basique.
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.
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:
-
faultcode: cet élément contient un code qui identifie l'erreur. SOAP définit 4
codes d'erreur, à savoir, VersionMismatch (namespace du bloc Envelope non
valide), MustUnderstand (un élément fils du bloc Header qui devait
absolument être compris ne l'a pas été), Client (message mal formatée ou non
valide), et Server (problème lors du traitement du message).
Le profil basique indique cependant que des codes d'erreurs supplémentaires peuvent être utilisés à condition que ceux-ci fassent parti d'un namespace spécifié (exemple: m:errorcode). - faultstring: cet élément contient un texte décrivant brièvement l'erreur pour un humain.
- faultactor: cet élément contient le composant (i.e., son URL) qui a généré l'erreur.
- detail: cet élément contient des informations spécifiques à l'application et concernant l'erreur.
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.