Error handling in SOAP Web Services – The Right Way

I have seen too many web services (and done a few) where fault handing is not user friendly / graceful.  Most of the times the way people code the web services using annotations or using POJOs in  frameworks like Axis2 the SOAP faults just contains an error message since this is the easiest thing to do. However for  clients this is not too friendly as they can only do error handling  based on your error strings. SOAP 1.2 specifications here , provide a better way of populating your SOAP faults. That is to provide at-least SOAP codes, sub-codes and a fault string as well as details (if possible). This is old news, but i still thought should be talked about. 

Consider the following example from the specifications

<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"
              xmlns:m="http://www.example.org/timeouts"
              xmlns:xml="http://www.w3.org/XML/1998/namespace">
 <env:Body>
  <env:Fault>
   <env:Code>
     <env:Value>env:Sender</env:Value>
     <env:Subcode>
      <env:Value>m:MessageTimeout</env:Value>
     </env:Subcode>
   </env:Code>
   <env:Reason>
     <env:Text xml:lang="en">Sender Timeout</env:Text>
   </env:Reason>
   <env:Detail>
     <m:MaxTime>P5M</m:MaxTime>
   </env:Detail>    
  </env:Fault>
 </env:Body>
</env:Envelope>

The above is an example of a well formated SOAP fault. The explanation of the elements of the message is below

Code : Code explains the nature of the fault. SOAP 1.2 specification recommends using the following “Code” values, even though i have seen other frameworks provide more types of codes. However keeping it to the list below should be sufficient.

VersionMismatch : If you do versioning in your web services and the SOAP request does not comply to the version of the API that you support, this should be the Code value specified in the SOAP fault. This version mismatch could be due to the mismatches in the “Envelop” element . You can use this code if you support SOAP 1.2 while the request is of version 1.1.

If you use this error code you should also provide an “Upgrade” element with “SupportedEnvelop” elements in your response which specifies the Envelop that you support for example

<?xml version="1.0" ?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"
              xmlns:xml="http://www.w3.org/XML/1998/namespace">
 <env:Header>
  <env:Upgrade>
   <env:SupportedEnvelope qname="ns1:Envelope" 
             xmlns:ns1="http://www.w3.org/2003/05/soap-envelope"/>
   <env:SupportedEnvelope qname="ns2:Envelope" 
             xmlns:ns2="http://schemas.xmlsoap.org/soap/envelope/"/>
  </env:Upgrade>
 </env:Header>
 <env:Body>
  <env:Fault>
   <env:Code><env:Value>env:VersionMismatch</env:Value></env:Code>
    <env:Reason>
      <env:Text xml:lang="en">Version Mismatch</env:Text>
    </env:Reason>
   </env:Fault>
 </env:Body>
</env:Envelope>

The example above uses the Upgrade element to specify that both Envelops of SOAP 1.1 and 1.2 are supported ( you can tell from the namespaces above for 1.1 and 1.2)

MustUnderstand : If the SOAP request contains elements in the “Header” section that you don’t understand , then using MustUnderstand code is the right way to go. If you use MustUnderstand code, then you must also provide an element in your fault called NotUnderstood. NotUnderstood element should contain the elements in the Header that you don’t understand. Consider the following request ( again the example is from the SOAP 1.2 specs )

<?xml version="1.0" ?>
<env:Envelope xmlns:env='http://www.w3.org/2003/05/soap-envelope'>
  <env:Header>
    <abc:Extension1 xmlns:abc='http://example.org/2001/06/ext'
       env:mustUnderstand='true'/>
    <def:Extension2 xmlns:def='http://example.com/stuff'
       env:mustUnderstand='true' />
  </env:Header>
  <env:Body>
    . . .
  </env:Body>
</env:Envelope>

In the request above lets say that the elements Extension1 and Extension2 are not understood by your Server. Then an appropriate response would be below

<?xml version="1.0" ?>
<env:Envelope xmlns:env='http://www.w3.org/2003/05/soap-envelope'
              xmlns:xml='http://www.w3.org/XML/1998/namespace'>
 <env:Header>
  <env:NotUnderstood qname='abc:Extension1'
                   xmlns:abc='http://example.org/2001/06/ext' />
  <env:NotUnderstood qname='def:Extension2'
                   xmlns:def='http://example.com/stuff' />
 </env:Header>
 <env:Body>
  <env:Fault>
   <env:Code><env:Value>env:MustUnderstand</env:Value></env:Code>
   <env:Reason>
     <env:Text xml:lang='en'>One or more mandatory 
       SOAP header blocks not understood
     </env:Text>
   </env:Reason>
  </env:Fault>
 </env:Body>
</env:Envelope>

You can see from the response above that the Code is MustUnderStand and the Header contains NotUnderstood element specifying which elements in the request were not understood and in this case they are Extension1 and Extension2

DataEncodingUnknown You use this fault code to report if you don’t support the encoding style sent in the SOAP request. This is not the encoding of the XML message, this relates to the encodingStyle attribute of the SOAP message elements. This attribute could be in the header in body or any of it’s subsequent elements.  If You don’t like what the client sent in this attribute you generate the SOAP fault using DataEncodingUnknown code.  If the client sends “http://www.w3.org/2003/05/soap-envelope/encoding/none&#8221; as encodingStyle it means no encoding rules apply.

Sender You should use this code to specify that the SOAP request was malformed or the fault is generated due to something the sender of the request did wrong. This can be missing a mandatory element in the request or data format errors or data type errors and so on. This basically tells the client that if they send the exact same message again without changing it, it will keep failing.

Receiver You should use this error code , if the fault is generated by no mistake of the client, but some error on the server side during processing of the message. This could be lets say unable to access your database, or any other coding issues that might have caused this fault. This tells the client that it may resend the request unchanged at a later time and it will succeed.

Subcode Subcodes should belong to their own namespace and are provided to give more information about the nature of the fault. It is up to you or the application developers to decide which Subcodes are provided by the application and what do they mean. These are application specific error codes and there is no limit of how many subcodes you can provide under a code. However it is best practice to keep number of sub-codes to as few as possible. You will send something like INV001 to indicate lets say an error in the Inventory system where it was not able to update the inventory count.. its a good practice to send one subcode at a time, so its clear to the clients what the actual error is.

Reason Reason is obviously some Free Text you would like to provide detailing your error string i.e “Unable to update inventory”.

Detail Details are optional details you might want to provide about your fault. It could very well be the stack trace to help debug the errors or can also contain the hint to the client about what is the valid value for something it didn’t provide.

One thought on “Error handling in SOAP Web Services – The Right Way

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s