Friday, 31 October 2014

OSB12c: Errorhandling in REST

Yesterday, I had an OSB consulting day at a customer. We looked into a REST service that was to be extended with update functionality. Since calling an update service of an EIS (Enterprise Information System) can go wrong with all sorts of errors, it is important to be able to return a fault-message with the errors, JSON format.

Now in OSB12c it's very apparent how you define possible fault-messages and even how the should be formatted in JSON:

In this sample case we created a more or less simple xsd for faults (dutch: fouten). To test with different fault messages we simply duplicated the 'fouten' element in the xsd to 'fouten2'. You can assign different HTTP-status codes to the different fault.

So this is configuration is pretty simple and straight forward. But it is not quite clear in the documents how you would return a specific fault within your error-handlers in the pipeline.

Internally OSB works not only 'XML'-based but actually SOAP-based. So the trick in the end is to replace the body with a soap-fault message and the selection of the REST/JSON errormessage is done based on the structure of the document in the details-section of the SOAP-Fault. In the screen above, you would define for each fault message an xsd-element and apparently it validates the soap-fault-details content against each XSD defined, and the xsd against which the detail-content is valid points to the returned fault, with the corresponding HTTP Status.

So we created a XQuery transformation as follows:
xquery version "1.0" encoding "utf-8";

(:: OracleAnnotationVersion "1.0" ::)

declare namespace ns2="http://darwin-it.nl/doe/mobile/fouten";
(:: import schema at "../PS/Schemas/fouten.xsd" ::)
declare namespace ns1="http://xmlns.oracle.com/adf/svc/errors/";
(:: import schema at "../BS/Schemas/XMLSchema_-130439696.xsd" ::)
declare namespace soap-env="http://schemas.xmlsoap.org/soap/envelope/";

declare variable $input as element() (:: schema-element(ns1:ServiceErrorMessage) ::) external;

declare function local:func($input as element() (:: schema-element(ns1:ServiceErrorMessage) ::)) as element() (:: schema-element(ns2:fouten) ::) {
      <soap-env:Fault>
         <faultcode>fault</faultcode>
         <faultstring></faultstring>
         <detail>
    <ns2:fouten>
        {
            for $detail in $input/ns1:detail
            return
            <ns2:ErrorMessages>
                <ns2:ErrorLevel>{fn:data($detail/ns1:severity)}</ns2:ErrorLevel>
                <ns2:ErrorMessage>{fn:concat("ERROR: ", fn:data($detail/ns1:message))}</ns2:ErrorMessage></ns2:ErrorMessages>
        }
    </ns2:fouten>
         </detail>
      </soap-env:Fault>  
};
 
local:func($input)
Of course the actual fault detail must follow the xsd for that particular fault. We tested but the faultcode or fault string does not have any affect in selection of the REST-fault or HTTP statuscode.
With the xquery above we got the 'fault' returned as defined in the REST definition, as shown in the screendump above.
 In our example, if we would changed the contents of this xquery and replace the tag <ns2:fouten> to <ns2:fouten2> then we got the other fault (fault2), with the corresponding HTTP-status.
A detail with contents that does not correspond to any of the defined fault-xsd's would result in HTTP-status 500: internal server error. So it is important to have a proper transformation where the returning fault-detail is valid to at least one of the fault-xsd's.

Another conclusion is that since the fault selection is apparently based on the detail-contents against the registered fault-xsd-elements, you apperently can't have different faults with the same xsd. Since JSON is 'namespace-less', you probably can solve this by defining several copies of the same xsd with a different namespace, one for each fault. The choosen namespace in the xquery would then be the selector for the fault. But since the underlying element names are the same, it would not differ in the resulting JSON-message. Of course in an XML result it would differ.

5 comments:

  1. Hi

    To get this to work where the error messages can be seen in the JSON response, I had to ensure that the following have NO namespace prefixes.





    Any child elements of "fouten" need the prefixes removed too.
    change to
    change to
    change to

    But the namespace prefix needs to stay on the "fouten" element


    Try this folks if you have issues.

    ReplyDelete
  2. Thanks for leaving this comment. Back then the xquery as proposed here worked for me. However, things have changed in the mean time. So it's good to have this suggestion.

    ReplyDelete
  3. Thank you.. it helped me to get things over the line

    ReplyDelete
  4. Hi...In rest service, Global handler when I am exposing the fault with failure i.e. reply with failure to client....in that case I'm not getting any fault code and fault message.... please help to resolve this issue....but when I'm exposing the the same service with reply with success in that scenario I'm getting the proper expected failure response i.e faultcode and fault message....please suggest for reply with failure case....

    ReplyDelete
  5. Hello,

    A post of 2014, but still it works. Thanks, you saved my day.

    ReplyDelete