5. SOAP Faults

A especificação do SOAP define uma metodologia para o relato de erros do servidor para o cliente. Já vimos exemplos em que o cliente verifica se ocorreram erros do lado do servidor e vai atuar de acordo com as situações detetadas. Nalguns casos os erros são gerados não por código de quem implementou o servidor mas automaticamente, por exemplo, quando um cliente invoca uma funcionalidade que não existe do lado do servidor.

Suponha que queríamos adicionar a verificação de tipos ao exemplo anterior. Podíamos verificar o tipo dos parâmetros enviados e gerar um erro para as situações anómalas: SOAP Fault. Note que nesta verificação teremos de ser um pouco permissivos para acomodar a tipagem implícita: quando estivermos à espera dum xsd:float também devemos aceitar um xsd:integer ou mesmo uma string (se esta contiver apenas digitos), ou seja, para um tipo mais específico devemos aceitar os menos específicos. Esta situação é normal se usarmos Forms para ler os argumentos ou passarmos estes no URL. Nestas situações o PHP assume sempre os valores como sendo do tipo string.

Apresentam-se a seguir as modificações introduzidas no servidor.

Exemplo 2.18. Verificação de tipos no servidor

...
function soma($n1, $n2) 
{    // verifica se é int ou se é uma string com um int
  if (!(( is_int($n1) || ctype_digit($n1) )&&( is_int($n2) || ctype_digit($n2) ))) 1
  {
    return new soap_fault('SERVER', '', 2
                          'n1 e n2 devem ser inteiros',  
                          'O valor recebido para n1 é '.gettype($n1).
                          ' e para n2 é '.gettype($n2));
  }  
  else
  {
    return new soapval('res', 'xsd:integer', $n1+$n2); 3
  }
}
...

1

É preciso alterar os métodos para incluir a verificação de tipos;

No caso do inteiro temos de verificar duas coisas: se o parâmetro é inteiro (e está tudo bem) ou se é uma string contendo apenas digitos;

A função is_int(var) verifica se var é do tipo inteiro;

A função ctype_digit(var) testa se var é uma string e neste caso se é composta apenas por digitos.

2

No método soap_fault os parâmetros têm a seguinte semântica:

  1. Quem originou o erro;

  2. Qual o código do erro (para os casos em que estejamos a implementar um protocolo com os códigos de erro bem definidos);

  3. Qual a situação anómala detetada;

  4. Informação mais específica sobre o erro detetado.

3

Com o método soapval constrói-se um resultado devidamente tipado. Os parâmetros são os seguintes:

  1. Nome da variável/elemento que irá conter o resultado;

  2. Tipo do resultado;

  3. Valor do resultado.


No nosso servidor temos dois serviços que tratam inteiros, como vimos acima, e temos dois serviços que lidam com números reais: a multiplicação e a divisão.

As modificações introduzidas nestes últimos apresentam-se a seguir.

Exemplo 2.19. Verificação de tipos nos métodos mul e div

...
function mul($n1, $n2)
{    // verifica se é float
  if (!(is_numeric($n1) && is_numeric($n2) )) 1
  {
    return new soap_fault('SERVER', '', 'n1 e n2 devem ser reais',  
                          'O valor recebido para n1 é '
                          .gettype($n1).
                          ' e para n2 é '.gettype($n2));
  }  
  else
  {
    return new soapval('res', 'xsd:float', $n1*$n2);
  }
}
...

1

A função is_numeric(var) testa se var é de um tipo numérico (inteiro ou real) ou se é uma string que contem um inteiro ou real.


O nosso cliente não precisa ser alterado. Relembre que os dois parâmetros lidos são usados para invocar todos os métodos. Como dois métodos aceitam parâmetros inteiros e os outros parâmetros reais, para um determinado par de parâmetros dois dos métodos irão originar erros. Vejamos as mensagens geradas para determinados pares de parâmetros.

Exemplo 2.20. Parâmetros inteiros: 7 e 5

Pedido SOAP
POST /nusoap-0.9.5/Soma2nums/serv-aritmetica3.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/Aritmetica/mul"
Content-Length: 532

<?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>
    <ns8216:div xmlns:ns8216="uri:ws.di.uminho.pt/Aritmetica">
      <n1 xsi:type="xsd:string">7</n1>
      <n2 xsi:type="xsd:string">5</n2>
    </ns8216:div>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Repare nos parâmetros que são enviados como xsd:string.

Resposta SOAP
HTTP/1.1 200 OK
Date: Wed, 19 Dec 2012 20:52:00 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: 510
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:divResponse xmlns:ns1="uri:ws.di.uminho.pt/Aritmetica">
      <res xsi:type="xsd:float">1.4</res>
    </ns1:divResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

O nosso cliente está a chamar os 4 métodos para o mesmo par de parâmetros. Cada chamada corresponde a um par de mensagens SOAP, pedido e resposta. Este par, pedido e resposta, correspondem à última chamada, para o método div.

Neste caso, como a divisão inteira não é exata o resultado devolvido é do tipo xsd:float. Vejamos um caso em que a divisão é exata.

Exemplo 2.21. Parâmetros inteiros: 8 e 4

Pedido SOAP
POST /nusoap-0.9.5/Soma2nums/serv-aritmetica3.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/Aritmetica/mul"
Content-Length: 532

<?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>
    <ns8216:div xmlns:ns8216="uri:ws.di.uminho.pt/Aritmetica">
      <n1 xsi:type="xsd:string">8</n1>
      <n2 xsi:type="xsd:string">4</n2>
    </ns8216:div>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Resposta SOAP
HTTP/1.1 200 OK
Date: Wed, 19 Dec 2012 20:52:00 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: 510
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:divResponse xmlns:ns1="uri:ws.di.uminho.pt/Aritmetica">
      <res xsi:type="xsd:int">2</res>
    </ns1:divResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

A figura seguinte mostra as respostas depois de tratadas pelo cliente.

Figura 2.5. Repostas do cliente aos parâmetros 8 e 4

Repostas do cliente aos parâmetros 8 e 4

Podemos observar que todos os resultados são inteiros apesar de termos indicado explicitamente que a divisão e a multiplicação retornariam resultados reais.

O contrário também se verifica se um dos parâmetros for real como já vimos atrás.