Skip to main content
Previous sectionNext section

SOAP Fault Handling

This chapter describes how to handle faults within a web service and within a web client.

For a detailed discussion of error processing, see the chapter on errors in the book Using Caché ObjectScript.

Note that the SOAPPREFIX parameter affects the prefix used in any SOAP faults; see “Specifying the SOAP Envelope Prefix” in the chapter “Fine-Tuning a Caché Web Service.”

Default Fault Handling in a Web Service

By default, when your Caché web service encounters an error, it returns a standard SOAP message containing a fault. The following shows an example (for SOAP 1.1). The SOAP envelope is omitted in this example:

<SOAP-ENV:Body>
 <SOAP-ENV:Fault>
  <faultcode>SOAP-ENV:Server</faultcode>
  <faultstring>Server Application Error</faultstring>
  <detail>
     <error xmlns='http://www.myapp.org' >
       <text>ERROR #5002: Cache error: <DIVIDE>zDivide^FaultEx.Service.1</text>
     </error>
  </detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
Copy code to clipboard

Returning Custom SOAP Faults in a Caché Web Service

To create and return a custom SOAP fault, do the following within the appropriate area of your code that traps errors:

  1. Create a fault object that contains the appropriate information. To do so, call one of the following methods of your web service: MakeFault(), MakeFault12(), MakeSecurityFault(), or MakeStatusFault(). These are discussed in the following subsection.

    Or create a fault object manually, as described in later in this chapter.

  2. Call the ReturnFault() method of the web service, passing the fault object as an argument. Note that ReturnFault()) does not return to its caller; it just sends the fault and terminates processing of the web method.

The following shows an example:

Method Divide(arg1 As %Numeric, arg2 As %Numeric) As %Numeric [ WebMethod ]
{
  Try {
    Set ans=arg1 / arg2
    } Catch {

        //<detail> element must contain element(s) or whitespace
        //specify this element by passing valid XML as string argument to MakeFault() 
        set mydetail="<mymessage>Division error detail</mymessage>"

        set fault=..MakeFault($$$FAULTServer,"Division error",mydetail)
        
        // ReturnFault must be called to send the fault to the client.
        // ReturnFault will not return here.
        Do ..ReturnFault(fault)
      }
  Quit ans
}
Copy code to clipboard

Methods to Create Faults

MakeFault()
classmethod MakeFault(pFaultCode As %String, 
                      pFaultString As %String, 
                      pDetail As %String = "", 
                      pFaultActor As %String = "") as %SOAP.Fault
Copy code to clipboard

Returns a fault object suitable for SOAP 1.1. Here:

  • pFaultCode is used within the <faultcode> element of the SOAP fault. Set this property equal to one of the SOAP 1.1 macros listed in “Macros for SOAP Fault Codes,” later in this chapter.

  • pFaultString is used within the <faultstring> element of the SOAP fault. Specify a string that indicates the reason for the fault, as intended for users to see.

  • pDetail is used within the <detail> element of the SOAP fault. Use this to specify information about the cause of the fault.

    If specified, this argument should be a string containing valid XML that can be used within the <detail> element. Caché does not verify that the string you provide is valid; it is the responsibility of your application to check this.

  • pFaultActor specifies the URI of the SOAP node on the SOAP message path that caused the fault to happen.

    This is useful if the SOAP message travels through several nodes in the SOAP message path, and the client needs to know which node caused the error. It is beyond the scope of this book to discuss this advanced topic.

MakeFault12()
classmethod MakeFault12(pFaultCode As %String, 
            pFaultString As %String,
            pDetail As %String = "", 
            pFaultActor As %String = "") as %SOAP.Fault
Copy code to clipboard

Returns a fault object suitable for SOAP 1.2. Use this method only the SoapVersion property of the web service is "1.2". For a discussion of how Caché handles the SOAP versions of request messages, see “Specifying Parameters of the Web Service,” earlier in this book.

For details on the arguments, see MakeFault().

MakeSecurityFault()
classmethod MakeSecurityFault(pFaultCode As %String, 
                              securityNamespace As %String) as %SOAP.Fault
Copy code to clipboard

Returns a fault object appropriate for a security failure. Specify FaultCode as one of the following: "FailedAuthentication", "FailedCheck", "InvalidSecurity", "InvalidSecurityToken", "SecurityTokenUnavailable", "UnsupportedAlgorithm", or "UnsupportedSecurityToken".

The namespace for this security fault is found in the SecurityNamespace property.

MakeStatusFault()
classmethod MakeStatusFault(pFaultCode As %String, 
                            pFaultString As %String, 
                            pStatus As %Status = "", 
                            pFaultActor As %String = "") as %SOAP.Fault
Copy code to clipboard

Returns a fault object based on a value in a %Status object.

pStatus is the %Status object to use.

For details on the other arguments, see MakeFault().

Macros for SOAP Fault Codes

The SOAP include file (%soap.inc) defines macros for some of the standard SOAP fault codes; these are listed in the following table. You can use these macros to specify SOAP fault codes. The table notes the version or versions of SOAP to which each macro applies.

ObjectScript Macros for SOAP Fault Codes
Macro SOAP Version(s) When to Use This Macro
$$$FAULTVersionMismatch 1.1 and 1.2 When the web service receives a SOAP message that contained an invalid element information item instead of the expected envelope element information item.
A mismatch occurs if either the namespace or the local name do not match.
$$$FAULTMustUnderstand 1.1 and 1.2 When the web service receives a SOAP message that contained an unexpected element that was marked with mustUnderstand="true"
$$$FAULTServer 1.1 When other server-side errors occur.
$$$FAULTClient 1.1 When the client made an incomplete or incorrect request.
$$$FAULTDataEncodingUnknown 1.2 When the arguments are encoded in a data encoding unknown to the receiver.
$$$FAULTSender 1.2 When the sender made an incomplete, incorrect, or unsupported request.
$$$FAULTReceiver 1.2 When the receiver cannot handle the message because of some temporary condition, for example, when it is out of memory.

Creating a Fault Object Manually

If you need more control than is given by the steps in the previous section, you can create and return a custom SOAP fault as follows:

  1. Create a fault object manually.

    To do so, create an instance of %SOAP.Fault (for SOAP 1.1) or %SOAP.Fault12 (for SOAP 1.2) and then set its properties, as described in the following sections.

    Note:

    You can use %SOAP.Fault in all cases. If a web service receives a SOAP 1.2 request and needs to return a fault, the web service automatically converts the fault to SOAP 1.2 format.

  2. Call the ReturnFault() method of the web service, passing the fault object as an argument. Note that ReturnFault()) does not return to its caller; it just sends the fault and terminates processing of the web method.

SOAP 1.1 Faults

This section provides information on %SOAP.Fault, which represents SOAP 1.1 faults. This section includes the following:

Example SOAP Fault

For reference, here is an example of a SOAP 1.1 fault, including the SOAP envelope:

<SOAP-ENV:Envelope 
xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' 
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' 
xmlns:s='http://www.w3.org/2001/XMLSchema' 
xmlns:flt="http://myfault.org" >
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
      <faultcode>SOAP-ENV:Server</faultcode>
      <faultstring>Division error</faultstring>
      <detail><mymessage>Division error detail</mymessage></detail>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Copy code to clipboard

%SOAP.Fault Properties

Caché represents a SOAP 1.1 fault as an instance of %SOAP.Fault, which has the following properties:

detail

Used within the <detail> element of the SOAP fault. Use this to specify information about the cause of the fault.

If specified, this argument should be a string containing valid XML that can be used within the <detail> element. Caché does not verify that the string you provide is valid; it is the responsibility of your application to check this.

faultcode

Used within the <faultcode> element of the SOAP fault. Set this property equal to one of the SOAP 1.1 macros listed in “Macros for SOAP Fault Codes,” earlier in this chapter.

faultstring

Used within the <faultstring> element of the SOAP fault. Specify a string that indicates the reason for the fault, as intended for users to see.

faultactor

Specifies the URI of the SOAP node on the SOAP message path that caused the fault to happen.

This is useful if the SOAP message travels through several nodes in the SOAP message path, and the client needs to know which node caused the error. It is beyond the scope of this book to discuss this advanced topic.

faultPrefixDefinition

Specifies a namespace prefix declaration that is added to the envelope of the SOAP fault. Use a value of the following form:

xmlns:prefix="namespace"
Copy code to clipboard

Where prefix is the prefix and namespace is the namespace URI.

For example:

 set fault.faultPrefixDefinition = "xmlns:FLT=""http://myfault.com"""
Copy code to clipboard

The %SOAP.Fault class also provides the AsString() method, which returns the fault object as a string.

SOAP 1.2 Faults

This section provides information on %SOAP.Fault12 and related classes, which represent SOAP 1.2 faults. This section includes the following:

Example SOAP Fault

For reference, here is an example of a SOAP 1.2 fault, including the SOAP envelope:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:flt="http://myfault.org">
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
      <SOAP-ENV:Code>
        <SOAP-ENV:Value>SOAP-ENV:Receiver</SOAP-ENV:Value>
      </SOAP-ENV:Code>
      <SOAP-ENV:Reason>
        <SOAP-ENV:Text xml:lang="en">Division error</SOAP-ENV:Text>
        <SOAP-ENV:Text xml:lang="it">Errore di applicazione</SOAP-ENV:Text>
        <SOAP-ENV:Text xml:lang="es">Error del uso</SOAP-ENV:Text>
      </SOAP-ENV:Reason>
      <SOAP-ENV:Detail><mymessage>Division error detail</mymessage></SOAP-ENV:Detail>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Copy code to clipboard

%SOAP.Fault12 Properties

The class %SOAP.Fault12 represents a SOAP 1.2 fault. This class has the following properties:

Code

An instance of %SOAP.Fault12.Code, discussed in the following section.

Detail

Used within the <detail> element of the SOAP fault. Use this to specify information about the cause of the fault.

If specified, this argument should be a string containing valid XML that can be used within the <detail> element. Caché does not verify that the string you provide is valid; it is the responsibility of your application to check this.

Node

Specifies the URI of the SOAP node on the SOAP message path that caused the fault to happen; optional for the destination node.

This is useful if the SOAP message travels through several nodes in the SOAP message path, and the client needs to know which node caused the error. It is beyond the scope of this book to discuss this advanced use of SOAP.

Reason

A list of instances of %SOAP.Fault12.Text, discussed in a following section. Each instance contains a reason string and a language code that indicates the language or locality of the reason string. These are used within the <Reason> element.

Role

Role that the node was operating in. See the preceding remarks for Node.

faultPrefixDefinition

Specifies a namespace prefix declaration that is added to the envelope of the SOAP fault. Use a value of the following form:

xmlns:prefix="namespace"
Copy code to clipboard

Where prefix is the prefix and namespace is the namespace URI.

For example:

 set fault.faultPrefixDefinition = "xmlns:FLT=""http://myfault.com"""
Copy code to clipboard

The %SOAP.Fault12 class also provides the AsString() method, which returns the fault object as a string.

%SOAP.Fault12.Code Properties

You use %SOAP.Fault12.Code as a value for the Code property of an instance of %SOAP.Fault12. The %SOAP.Fault12.Code class has the following properties:

Subcode

An optional subcode.

Value

The value you provide depends on whether you have provided a subcode:

  • If you used a subcode, specify Value as a qname.

  • If you did not use a subcode, specify Value as one of the SOAP 1.2 macros listed in “Macros for SOAP Fault Codes,” earlier in this chapter.

%SOAP.Fault12.Text Properties

You use %SOAP.Fault12.Text as a list element in the Reason property of an instance of %SOAP.Fault12. The %SOAP.Fault12.Text class has the following properties:

Text

A string indicating the reason for the fault, as intended for users to see.

lang

A code that corresponds to the language or locality in which the fault text is phrased. For information, see the W3 web site (https://www.w3.org/).

Adding WS-Addressing Header Elements When Faults Occur

Your Caché web service can add WS-Addressing header elements when faults occur. To do this, include the following additional steps within the fault handling of your web service:

  1. Choose a fault destination and a fault action to use in case of faults.

  2. Using these as arguments, call the GetDefaultResponseProperties() class method of %SOAP.Addressing.Properties. This returns an instance of %SOAP.Addressing.Properties that is populated with values as typically needed.

  3. Optionally set other properties of the instance of %SOAP.Addressing.Properties, as needed.

    For details, see the class documentation for %SOAP.Addressing.Properties.

  4. Set the FaultAddressing property of your web service equal to the instance of %SOAP.Addressing.Properties.

Adding Other Header Elements When Faults Occur

In addition to or instead of the options discussed in the previous section, your Caché web service can add custom header elements when faults occur. To do this:

  1. Create a subclass of %SOAP.Header. In this subclass, add properties to contain the additional data.

    See the chapter “Adding and Using Custom Header Elements.”

  2. Within the fault handling of your web service (as described earlier in this chapter), include the following additional steps:

    1. Create an instance of your header subclass.

      Note:

      Despite the name of this class, this object is really a SOAP header element, not an entire header. A SOAP message has one header, which contains multiple elements.

    2. Set its properties as needed.

    3. Insert this header element into the FaultHeaders array property of the web service. To do so, call the SetAt() of that property. The key that you provide is used as the main header element name.

For example, consider the following custom header class:

Class Fault.CustomHeader Extends %SOAP.Header
{

Parameter XMLTYPE = "CustomHeaderElement";

Property SubElement1 As %String;

Property SubElement2 As %String;

Property SubElement3 As %String;

}
Copy code to clipboard

We could modify the web method shown previously as follows:

Method DivideAlt(arg1 As %Numeric, arg2 As %Numeric) As %Numeric [ WebMethod ]
{
  Try {
    Set ans=arg1 / arg2
    } Catch {

        //<detail> element must contain element(s) or whitespace
        //specify this element by passing valid XML as string argument to MakeFault() 
        set mydetail="<mymessage>Division error detail</mymessage>"

        set fault=..MakeFault($$$FAULTServer,"Division error",mydetail)

        //Set fault header
        Set header=##class(CustomHeader).%New()
        Set header.SubElement1="custom fault header element"
        Set header.SubElement2="another custom fault header element"
        Set header.SubElement3="yet another custom fault header element"
        Do ..FaultHeaders.SetAt(header,"CustomFaultElement")

        // ReturnFault must be called to send the fault to the client.
        // ReturnFault will not return here.
        Do ..ReturnFault(fault)
      }
  Quit ans
}
Copy code to clipboard

When the web client invokes the Divide() web method and uses 0 as the denominator, the web service responds as follows:

<?xml version='1.0' encoding='UTF-8' standalone='no' ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' 
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' 
xmlns:s='http://www.w3.org/2001/XMLSchema' xmlns:flt="http://myfault.org" >
  <SOAP-ENV:Header>
<CustomHeaderElement xmlns:hdr="http://www.mynamespace.org">
    <SubElement1>custom fault header element</SubElement1>
    <SubElement2>another custom fault header element</SubElement2>
    <SubElement3>yet another custom fault header element</SubElement3>
</CustomHeaderElement>
</SOAP-ENV:Header>
  <SOAP-ENV:Body>
...
Copy code to clipboard

Here line breaks were added for readability.

Handling SOAP Faults and Other Errors in a Caché Web Client

In a Caché web client, you can use the TRY-CATCH mechanism or the older $ZTRAP mechanism.

In either case, when a Caché web client receives an error, Caché sets the special variables $ZERROR and %objlasterror:

  • If the error is a SOAP fault, the value of $ZERROR starts with <ZSOAP>, and %objlasterror contains the status error that is formed from the received SOAP fault.

    In addition, the client instance has a property named SoapFault, which is an instance of %SOAP.Fault or %SOAP.Fault12 (depending on the SOAP version used in the web service). You can use the information in this property. For more information on %SOAP.Fault and %SOAP.Fault12, see the previous sections.

  • If the error is not a SOAP fault, use your normal error handling (typically using $ZERROR). It is your responsibility to specify how to proceed.

Example 1: Try-Catch

The following method uses TRY-CATCH:

ClassMethod Divide(arg1 As %Numeric, arg2 As %Numeric) As %Numeric
{
    Set $ZERROR=""
    Set client=##class(FaultClient.DivideSoap).%New()

    Try {
        Set ans=client.Divide(arg1,arg2)
        }
    Catch {
        If $ZERROR["<ZSOAP>" {
            Set ans=%objlasterror
            } 
            Else {
            Set ans=$$$ERROR($$$CacheError,$ZERROR)
        }
    }
    
    Quit ans
}
Copy code to clipboard

This method uses system macros defined in the %systemInclude include file, so the class that contains this method starts with the following:

Include %systemInclude 
Copy code to clipboard

Example 2: $ZTRAP

The following example uses the older $ZTRAP mechanism. In this case, when a Caché web client receives an error, control is transferred to the label indicated by the $ZTRAP special variable (if that label is defined).

ClassMethod DivideWithZTRAP(arg1 As %Numeric = 1, arg2 As %Numeric = 2) As %Numeric
{
    Set $ZERROR=""
    Set $ZTRAP="ERRORTRAP"
    Set client=##class(FaultClient.DivideSoap).%New()
    Set ans=client.Divide(arg1,arg2)
    Quit ans
 
    //control goes here in case of error
ERRORTRAP 
    if $ZERROR["<ZSOAP>" 
    {
         quit client.SoapFault.Detail
        } 
    else 
    {
        quit %objlasterror
       }
}
Copy code to clipboard

SSL Handshake Errors

If a Caché web client uses an SSL connection and a SSL handshake error has occurred, then the SSLError property of the client contains text that describes the SSL error.