Capítulo 1. SOAP

Simple Object Access Protocol

Índice

1. Mensagem SOAP
1.1. Envelope
1.2. Header
1.3. Body
1.4. Fault
2. Tipos de dados
2.1. Tipos simples
2.2. Tipos estruturados
2.2.1. Arrays
2.2.2. Produto cartesiano (structs)
2.2.3. Listas de estruturas
3. Alguns exemplos de extensões SOAP
3.1. Security Assertion Markup Language (SAML)

O SOAP foi criado com o intuito de ser um protocolo de comunicação simples (pouco exigente), baseado em XML e destinado à troca de informação tipada e estruturada entre aplicações distribuídas e descentralizadas.

De forma a não comprometer a independência em relação às plataformas de desenvolvimento, o SOAP não define um protocolo de transporte para o envio de mensagens, apesar de possuir uma descrição de como deve ser utilizado sobre HTTP. A existência desta descrição deve-se ao facto do HTTP ser o protocolo standard para a Internet. No entanto, o SOAP não se encontra vinculado ao HTTP, podendo utilizar uma grande variedade de outros protocolos. Por exemplo: FTP - File Transfer Protocol, SMTP - Simple Mail Transfer Protocol, BEEP - Blocks Extensible Exchange Protocol.

1. Mensagem SOAP

O intercâmbio de informação é efectuado através de mensagens em formato XML, estando a cargo do SOAP a definição desse mesmo formato. Uma mensagem é essencialmente uma transmissão unidireccional no sentido emissor/receptor, no entanto, estas podem ser combinadas de forma a incluir numa única mensagem a informação relativa ao pedido e à resposta, tornando-a assim uma transmissão bidireccional.

Cada mensagem é um documento XML com o seu próprio Schema, os seus próprios Namespaces, elementos e atributos, o que não é de estranhar pois não podemos esquecer que SOAP é baseado em XML. Como se sabe (???), os Namespaces permitem definir univocamente os elementos e/ou atributos de cada documento XML proveniente de Schemas} diferentes, e o SOAP tem pré-definidas duas famílias/grupos de elementos e atributos: SOAP envelope e SOAP serialization ou SOAP encoding. Uma das regras a ter em conta na definição das mensagens é a de que não podem ter DTDs associados, ou seja a declaração DOCTYPE não pode estar presente.

Para uma mais fácil percepção do que é uma mensagem SOAP, é muitas vezes estabelecida a analogia com uma carta de correio. A razão de tal analogia reside no facto da estrutura de uma mensagem SOAP se encontrar dividida em três secções: o envelope, o cabeçalho e o corpo (Figura 1.1, “Estrutura de uma mensagem SOAP”).

Figura 1.1. Estrutura de uma mensagem SOAP

Estrutura de uma mensagem SOAP

Como podemos verificar, o envelope envolve toda a mensagem sendo constituído por um cabeçalho e um corpo. Dentro do corpo encontramos o conteúdo (informação) da mensagem e, no cabeçalho, a identificação sobre a natureza desse mesmo conteúdo. É óbvio que esta é ainda uma visão generalista da constituição de uma mensagem SOAP.

Até agora tem-se vindo a falar em mensagens SOAP, mas ainda nenhuma foi apresentada. Vejamos então um exemplo de mensagens SOAP de pedido/resposta relativo a um Web Service muito simples que devolve a string "Hello" concatenada com o parâmetro que lhe é passado.

Exemplo 1.1. Um Pedido SOAP

POST /nusoap-0.9.5/Hello/serv-hello-ns.php HTTP/1.0
Host: localhost:8888
User-Agent: NuSOAP/0.9.5 (1.123)
Content-Type: text/xml; charset=ISO-8859-1
SOAPAction: "uri:ws.di.uminho.pt/Hello/hello"
Content-Length: 522

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope 
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns9531:hello xmlns:ns9531="uri:ws.di.uminho.pt/Hello">  1
      <name xsi:type="xsd:string">José Carlos Ramalho</name> 2
    </ns9531:hello>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

1

Nome do método a invocar;

2

Parâmetro do método que se está a invocar.


Exemplo 1.2. Uma Resposta SOAP

HTTP/1.1 200 OK
Date: Fri, 14 Dec 2012 10:45:53 GMT
Server: Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8r DAV/2 PHP/5.3.6
X-Powered-By: PHP/5.3.6
X-SOAP-Server: NuSOAP/0.9.5 (1.123)
Content-Length: 529
Connection: close
Content-Type: text/xml; charset=ISO-8859-1

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope 
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:helloResponse xmlns:ns1="uri:ws.di.uminho.pt/Hello">  1
      <return xsi:type="xsd:string">Hello, José Carlos Ramalho</return> 2
    </ns1:helloResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

1

Resposta à invocação do método, designada por helloResponse;

2

Valor devolvido pelo método invocado.


Como facilmente se verifica , os Namespaces assumem um papel preponderante em qualquer das mensagens apresentadas. Tal facto deve-se, como por esta altura o leitor deverá ser capaz de responder, à necessidade de evitar conflitos com os nomes dos elementos e atributos das diferentes mensagens SOAP.

Em ambas as mensagens apresentadas surge, na maioria dos elementos, um prefixo soap definido na declaração do Namespace:

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"

No entanto, este prefixo não é obrigatório nem mesmo pré-estabelecido, podendo-se optar por qualquer outro que pareça mais adequado. Os prefixos normalmente utilizados são: soap e SOAP-ENV.

No exemplo apresentado é possível encontrar os principais elementos de uma mensagem: Envelope, Header e Body. No entanto, existe ainda um outro elemento pré-definido Fault, sobre o qual nos debruçaremos mais à frente.

Antes de analisarmos cada um dos elementos referidos, é necessário compreender alguns dos conceitos simples, mas sem os quais a compreensão da estrutura de uma mensagem SOAP se tornará penosa.

Tal como foi referido anteriormente a troca de mensagens envolve essencialmente duas partes: o emissor e o receptor. A cada receptor que executa algum processamento sobre a mensagem, chamamos: endpoint ou ponto terminal. É da responsabilidade do ponto terminal a análise da mensagem e a remoção da parte que lhe é endereçada. No entanto, cada ponto terminal pode ser simultaneamente receptor e emissor, sendo então designado por intermediário}. Perante uma mensagem SOAP cada ponto terminal/intermediário executa três operações:

  • Análise da mensagem e verificação se alguma parte da mesma lhe é endereçada;

  • Verificação se alguma das partes que se lhe são dirigidas é de execução obrigatória. Se conseguir executar as operações processa a mensagem, caso contrário rejeita-a;

  • Se se trata de um intermediário, então é necessário retirar todas as partes identificadas na 1ª operação e só depois enviar a mensagem ao próximo ponto terminal.

Para uma percepção gráfica da forma como se processa a troca de mensagens SOAP entre emissor(es) e receptor(es) ver Figura 1.2, “Troca de mensagens SOAP”.

Figura 1.2. Troca de mensagens SOAP

Troca de mensagens SOAP

1.1. Envelope

Relativamente ao elemento Envelope, este apresenta-se como o elemento raiz de uma mensagem SOAP, correspondendo portanto à descrição da mensagem e do que deve ser processado. Este elemento tem como Namespace obrigatório a string: http://schemas.xmlsoap.org/soap/envelope/. Analisando a última mensagem apresentada (Exemplo 1.2, “Uma Resposta SOAP”), verificamos a existência do atributo opcional, encodingStyle, o qual pode ser usado para definir a forma como os dados serão representados na mensagem. Este atributo pode aparecer em qualquer elemento da mensagem, no entanto, no caso do SOAP, o atributo encodingStyle aparece usualmente no elemento Envelope.

Por esta altura já verificámos o uso dos Namespaces nas mensagens SOAP, no entanto, os XML Schemas (xsd) ainda não foram referidos. No Encoding pode-se utilizar Schemas para efectuar a validação e conversão de tipos. Como facilmente se constata pelo exemplo anterior, o valor do atributo encodingStyle é um URI (http://schemas.xmlsoap.org/soap/encoding/), o qual aponta para um Schema. Apesar de opcional, este atributo deve ser sempre indicado para permitir a identificação dos tipos de dados, que podem ser simples e/ou complexos.

1.2. Header

Apesar de todas as potencialidades do SOAP, ele apresenta, quer por opção na altura do seu desenvolvimento quer por razões que têm a ver com a independência de plataformas de desenvolvimento, algumas limitações a nível de segurança, reencaminhamento e transacções, entre outros. No entanto, é possível adicionar ao SOAP módulos designados por extensões, os quais permitem adicionar funcionalidades não implementadas pelo SOAP. É nestes casos que o elemento Header se torna importante.

O elemento Header é opcional e tem como função estender as funcionalidades das mensagens SOAP. Desta forma é possível adicionar novas funcionalidades à mensagem, tais como autenticação, transacções, encriptação, sem ser necessário alterar as especificações do SOAP, permitindo deste modo manter a interoperabilidade de sistemas (Secção 3, “Alguns exemplos de extensões SOAP”). Este elemento, no caso de existir, tem de ser o primeiro "filho" do elemento Envelope. O cabeçalho (Header) contém um ou mais sub-elementos, os quais designamos por entradas. Os pontos terminais ao receberem a mensagem vão verificar se existe alguma entrada que lhes seja endereçada e, em caso afirmativo, determinam qual a acção a executar com a informação contida no elemento Body da mensagem SOAP. Desta forma, é possível ir adicionando entradas/extensões ao longo do tempo, sem criar incompatibilidades com pontos terminais já existentes.

Dentro do elemento Header convém salientar dois atributos importantes:

actor

Vimos anteriormente que os pontos terminais irão procurar informação nas entradas do Header para saber se existe alguma informação que lhes seja dirigida. Este atributo permite identificar a que ponto terminal se destina o elemento Header. Para tal, o SOAP reconhece dois valores possíveis: http://schemas.xmlsoap.org/soap/actor/next, o qual indica que a entrada é dirigida ao primeiro ponto terminal que a encontrar, e o valor obtido por omissão do atributo, o qual indica que se destina ao ponto terminal final, i.e., ao ponto terminal que vai tratar o corpo da mensagem;

mustUnderstand

No envio de uma mensagem SOAP, está implícito o facto do ponto terminal saber como processar a mensagem. Contudo, um ponto terminal pode ou não saber como lidar com determinada entrada do cabeçalho, mas ao mesmo tempo ser capaz de processar correctamente a mensagem. Se o emissor quiser garantir que o receptor sabe como lidar com determinada entrada do cabeçalho, basta colocar o atributo mustUnderstand com o valor true ou o equivalente binário 1. No caso deste atributo se encontrar presente e o ponto terminal não ser capaz de lidar com a entrada do cabeçalho que lhe é endereçado, o ponto terminal deve rejeitar toda a mensagem.

1.3. Body

O elemento Body é um elemento obrigatório de qualquer mensagem SOAP e nele encontramos a informação propriamente dita.

Na primeira mensagem apresentada, Exemplo 1.1, “Um Pedido SOAP”, podemos ver a chamada a um método hello, na qual é passado um parâmetro correspondendo ao nome da pessoa que se quer cumprimentar.

Dentro do corpo de uma mensagem podemos encontrar desde simples chamadas a métodos, até stylesheets, ou qualquer outro tipo de informação, em formato XML, que se pretenda transferir através de uma mensagem. O conteúdo da mensagem é representado através de elementos do Body, e é serializável de acordo com as definições escolhidas, ou seja, de acordo com o encodingStyle escolhido.

1.4. Fault

Até agora foi apresentada a estrutura de uma mensagem SOAP partindo do pressuposto que tudo corre bem, i.e., onde não existem erros durante o envio e processamento das mensagens. Mas na vida real as aplicações não são tão bem comportadas, existem sempre imprevistos que prejudicam o correcto funcionamento de um Web Service. Para fazer face a estes problemas existe um sub-elemento, opcional, do elemento Body, que representa um erro na mensagem SOAP. Estamos a falar do elemento Fault, através do qual é possível dar uma localização e formato aos erros.

Exemplo 1.3. Elemento Fault numa mensagem SOAP

A seguir, mostra-se um exemplo de uma mensagem de resposta com um elemento Fault. Este exemplo corresponde a uma aplicação, discutida mais à frente, que fornece um serviço aritmético em que duas das funcionalidades recebem parâmetros inteiros e outras duas parâmetros reais. A mensagem apresentada é gerada quando com um dos métodos que deve receber parâmetros inteiros é invocado com parâmetros reais.

HTTP/1.0 500 Internal Server Error
Date: Tue, 28 Aug 2012 17:02:53 GMT
Server: Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8r DAV/2 PHP/5.3.6
X-Powered-By: PHP/5.3.6
Status: 500 Internal Server Error
X-SOAP-Server: NuSOAP/0.9.5 (1.123)
Content-Length: 705
Connection: close
Content-Type: text/xml; charset=ISO-8859-1

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
      <faultcode xsi:type="xsd:string">Sender</faultcode>
      <faultactor xsi:type="xsd:string">uri:ws.di.uminho.pt/Aritmetica/soma</faultactor>
      <faultstring xsi:type="xsd:string">n1 e n2 devem ser inteiros</faultstring>
      <detail xsi:type="xsd:string">O valor recebido para n1 é string e para n2 é string</detail>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

No caso deste exemplo, todo o elemento Fault foi construído pelo servidor tendo sido programada a sua geração.


O elemento Fault corresponde a um registo constituído pelos seguintes campos:

faultcode

Elemento que contém um valor identificativo da falta. A última especificação do SOAP tem uma lista pré-definida dos tipos de faltas que pode eventualmente ser estendida em caso de necessidade:

VersionMismatch

Este é o código gerado quando as versões do SOAP, entre cliente e servidor, não batem certo, ou quando os NameSpaces dos dois lados não coincidem;

MustUnderstand

No pedido, vinha um elemento no Header indicando que o servidor para poder responder teria que entender uma certa funcionalidade, quando isso não acontece é este o código gerado;

DataEncodingUnknown

No pedido, no Header ou num elemento do Body há um elemento que tem um encoding especificado que não reconhecido ou suportado do lado do servidor;

Sender

A mensagem do pedido não está formada corretamente, ou por má construção ou simplesmente porque falta um elemento obrigatório para que o servidor possa satisfazer o pedido;

Receiver

O pedido não pode ser respondido por dificuldades no servidor, por algum motivo uma ou várias das tarefas que teria de realizar não foram realizadas.

faultstring

Elemento que contém uma descrição da falha. No exemplo apresentado, a falha é devida a um type mismatch;

faultactor

contém um URI com a identificação do ponto terminal que origina a falha. A ausência deste elemento indica que o erro aconteceu no endpoint final;

detail

A especificação deste elemento torna-se obrigatória quando ocorrem problemas no processamento da mensagem por parte do servidor, ou seja, no caso em que o elemento faultcode toma o valor Receiver. Nele podem ser encontrados alguns detalhes da falha, tais como o módulo e linha de código onde ocorreu o erro.

Termina aqui a descrição da estrutura duma mensagem SOAP. Na próxima secção, discute-se com mais detalhe a utilização de tipos de dados para caracterizar os parâmetros de entrada e de saída das funcionalidades expostas por um Web Service.