Web Service can response with a Fault in 2 occasions.
- Fault send by the web service framework. (E.g. Invalid authentication, invalid signature found)
- Fault send by the user business logic.
There is a slightly difference in the content of SOAP 1.1 and SOAP 1.2. But they mainly contain the following elements.
- Code – A code to represent the classification of the fault. Possible fault codes can be found, http://www.w3.org/TR/soap12-part1/#faultcodes
- Reason – A human readable details of the reason.
- Details – More information about the details, mostly supposed to be read by the client application.
- Role – Indicates which SOAP header caused the fault. This is very rarely used in faults send from the business logic.
Sending SOAP Faults
In WSF/PHP you have the WSFault class to deal with SOAP faults. You can send a fault in your service logic by throwing an instance of WSFault class like this.
/** * divide mathematical operation * @param int $dividend * (maps to xs:int) * @param int $divisor * (maps to xs:int) * @return float $result * (maps to xs:float) */ function divide($dividend, $divisor) { // dividing from 0 is invalid, we wil *throw* fault in such cases.. if($divisor == 0) { throw new WSFault("Sender", "dividing from 0 is invalid"); } $result = (float)$dividend/$divisor; return array("result" => $result); }
Here I have throw an WSFault whenever I encounter my divisor is zero. And the WSF/PHP will take care of building the SOAP message according to the given version (default is to SOAP 1.2) and send back to the client.
Handling SOAP Faults
Similar to the service, client API also treat the SOAP fault as an instance of WSFault. So whenever you do a web service request, put inside try, catch block so you can catch exception in case of fault is received. Here is an example of handling fault while calling the divide operation in the above example.
// creating the client, we retrieved the wsdl from service url + ?wsdl $client = new WSClient(array( "wsdl" => "http://localhost/myblog/fault_service.php?wsdl")); $proxy = $client->getProxy(); try { // calling the operation $response = $proxy->divide(array("dividend" => 5, "divisor" => 0)); // printing the result echo $response["result"]; } catch(Exception $e) { // if the instance is WSFault we print the code and the reason if ($e instanceof WSFault) { printf("Soap Fault Reason: %s\n", $e->Reason); printf("Soap Fault Code: %s \n", $e->Code); } else { printf("Message = %s\n",$e->getMessage()); } }
As you can see WSF/PHP covers the complexity of building and handling SOAP faults, Rather it gives you an API with the use of PHP Exception Construct that you already familiar with.
I am curious if you still get an error on the client side if you make the function divivide void, i.e. make it to return nothing. Could you try it?
Hi FooBar,
Ok, I make it to return nothing and I got this response payload back.
<ns1:divideResponse xsi:nil=”1″ xmlns:ns1=”http://www.wso2.org/php/xsd” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”/>
which represent the nil response.
Thanks
Dimuthu
Hi Again,
You are asking whether I get an error in the client side for that situation. In fact no. It actually results a NULL value. Yea I put this at the end,
if($response[“result”] === NULL) {
echo “The result === NULL”;
}
and observe actually it prints “The result === NULL”. Here the result is not equal to 0. It is pure NULL in PHP. That’s what triple equal operator means. FYI http://www.dzone.com/links/r/triple_equal_operator_and_null_in_php.html
Thanks
Dimuthu
Hi Dimuthu, thanks for checking! I used the php built-in SoapServer and a SoapClient and those from the Zend Framework. When I throw an exception in a void method, the client doesn’t recieve that exception.
I’ve looked in the w3c specs, and couldn’t find a definitive answer on the question wether a soap-server should return a fault in one-way communication.
If one says that in one-way communication the client doesn’t expect a response, then there shouldn’t be a nill response at all.
I for one would suspect that the client always get an exception from the server if the server didn’t handle it itselves.
Do you agree?
Hi FooBar,
I too haven’t read about this in specs. But I have familiar with the Apache Axis2/C and Axis2/Java Clients APIs for invoking Services with In-Only Message Exchange Pattern. They Provide 2 API functions for that.
1. fire_and_forget – Send the request, but doesn’t wait for anything
2. send_robust – Send the request, and wait for the fault or “202 OK Accepted” HTTP Status (Apparently only in HTTP).
So it’s look like Specs allow for both of these scenarios. Anyway I will check more on this and let you know if anything new.
Many thanks for your follow-up. I am very happy to learn more!
Hi Dimuthu,
You seem to have good expertise in PHP SOAP.
I am using PHP-5.2.6’s inbuilt SOAP extension. I am doing ‘fire and forget’ using one-way communication and for the same I have an entry in WSDL and also the server method returns void. But what if there is an exception thrown at server? How do the client know it and take necessary action?
Is there any workaround?
Hi Naveen,
I’ve not tested this scenario in PHP SOAP extension. But I can say exactly what happens in WSF/PHP, if you use it in both client and server.
Whenever the server throws an excpetion with a type WSFault class, the server actually send the client a SOAP fault message in the wire. In the client side you can handle this as just another exception, but again with type WSFault.
check source for sample fault_service.php: http://labs.wso2.org/wsf/php/source_page_old.php?src=solutions%2Fsamples%2Ffault_service.php
and the fault_client.php: http://labs.wso2.org/wsf/php/source_page_old.php?src=solutions%2Fsamples%2Ffault_client.php
Hope this will help!.
Thanks
Dimuthu