Handling Faults

Not applicable

I just can't get my head wrapped around how to handle different faults. I need to capture the faults and send back a custom XML response to the clients. I have tried several different ways to do this but have not been able to get the custom response to be sent. I can see in the trace where the check was made but the step was skipped because the condition did not match. In this API i would need to set a couple of different fault rules. One for the schema validation and one if the target server is not available. I'm sure I will need to add more as I go along. Not sure how to set this up, any help would be greatly appreciated.

Below is my proxy endpoint and my target endpoint.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <FaultRules/>
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>Set-Content-Type</Name>
            </Step>
            <Step>
                <Name>SubscriberInquiry-Validation</Name>
            </Step>
            <Step>
                <Name>SubscriberInquiry_req</Name>
            </Step>
            <Step>
                <Name>Extract-Header-Values</Name>
            </Step>
            <Step>
                <Name>Assign-Header-Values</Name>
            </Step>
        </Request>
        <Response>
            <Step>
                <Name>SubscriberInquiry_rep</Name>
            </Step>
        </Response>
    </PreFlow>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
    <Flows/>
    <HTTPProxyConnection>
        <BasePath>/ejav-eps-subscriberinquiry-service</BasePath>
        <Properties/>
        <VirtualHost>default</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="SubscriberInquiry">
        <TargetEndpoint>TargetEndpoint-SubscriberInquiry</TargetEndpoint>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
    </RouteRule>
</ProxyEndpoint>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TargetEndpoint name="TargetEndpoint-SubscriberInquiry">
    <Description/>
    <FaultRules/>
    <PreFlow name="PreFlow">
        <Request/>
        <Response/>
    </PreFlow>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
    <Flows/>
    <HTTPTargetConnection>
        <LoadBalancer>
            <Server name="ejav-eps-target-inquiry-1"/>
            <Server name="ejav-eps-target-inquiry-2"/>
        </LoadBalancer>
        <Path>/Eps/EPSHttpService</Path>
    </HTTPTargetConnection>
</TargetEndpoint>
0 5 577
5 REPLIES 5

One way to achieve this is by :
  • Creating a Shared flow which can produce a standardized custom representation of your error.
  • Attach the Shared Flow as a Default Fault Rule to all Proxy and Target Endpoints
<ProxyEndpoint name="default">
    <Description/>
    <FaultRules/>
    <DefaultFaultRule name="all">
        <AlwaysEnforce>true</AlwaysEnforce>
          <Step>
            <Name>my-fault-handling-flow</Name>
        </Step>
    </DefaultFaultRule>

Now, there are two/three primary ways in which an error occurs in an Apigee proxy

  1. Operational Errors - 401,403, 500 from target,etc.). Any of these errors would automatically put your proxy into the error flow and you would have a chance to inspect the error and customize it
  2. Programmer Errors(Bugs) - Handled same as above.
  3. Validation Errors - You validate input and you find that the client request does not match expectations. I often use a javascript policy (and not a RaiseFault policy with a condition) to validate such conditions and throw an error. When i throw such an error, i put custom variables into the context before i throw the error. My error handling shared flow examines these custom context variables to build a standardized yet rich error structure

Hope this helps

@rmishra I set up the DefaultFaultRule, which is trapping all of the errors. The issue I have now is I am attempting to transform the fault to XML using JSONToXML, setting the content-type back to application/xml then doing a XML transformation to send back a XML formatted response to the client. I don't then the JSONToXML is working which causes a error when I try to reset the content-type - Unexpected character ({) at position 0, therefore the XSL transformation never occurs.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <FaultRules/>
    <DefaultFaultRule name="all">
        <AlwaysEnforce>true</AlwaysEnforce>
        <Step>
            <Name>ConvertFault</Name>
        </Step>
        <Step>
            <Name>Set-Content-Type</Name>
        </Step>
        <Step>
            <Name>SystemError</Name>
        </Step>
    </DefaultFaultRule>
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>Set-Content-Type</Name>
            </Step>
            <Step>
                <Name>SubscriberInquiry-Validation</Name>
            </Step>
            <Step>
                <Name>SubscriberInquiry_req</Name>
            </Step>
            <Step>
                <Name>Extract-Header-Values</Name>
            </Step>
            <Step>
                <Name>Assign-Header-Values</Name>
            </Step>
        </Request>
        <Response>
            <Step>
                <Name>SubscriberInquiry_rep</Name>
            </Step>
        </Response>
    </PreFlow>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
    <Flows/>
    <HTTPProxyConnection>
        <BasePath>/ejav-eps-subscriberinquiry-service</BasePath>
        <Properties>
            <Property name="success.codes">4xx,5xx</Property>
        </Properties>
        <VirtualHost>default</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="SubscriberInquiry">
        <TargetEndpoint>TargetEndpoint-SubscriberInquiry</TargetEndpoint>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
    </RouteRule>
</ProxyEndpoint>

JSONToXML

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<JSONToXML async="false" continueOnError="false" enabled="true" name="ConvertFault">
    <DisplayName>ConvertFault</DisplayName>
    <Properties/>
    <Options>
        <NullValue>NULL</NullValue>
        <NamespaceBlockName>#namespaces</NamespaceBlockName>
        <DefaultNamespaceNodeName>$default</DefaultNamespaceNodeName>
        <NamespaceSeparator>:</NamespaceSeparator>
        <TextNodeName>#text</TextNodeName>
        <AttributeBlockName>#attrs</AttributeBlockName>
        <AttributePrefix>@</AttributePrefix>
        <InvalidCharsReplacement>_</InvalidCharsReplacement>
        <ObjectRootElementName>Root</ObjectRootElementName>
        <ArrayRootElementName>Array</ArrayRootElementName>
        <ArrayItemElementName>Item</ArrayItemElementName>
    </Options>
    <OutputVariable>response</OutputVariable>
    <Source>request</Source>
</JSONToXML>

Can this process even happen?

@Rick Decker When you say that you are trying to convert a fault to an XML, what kind of Fault are you talking about - An error in the apigee context , A Soap Fault?

If there is an error in the apigee context which you created (request validation failure)/ apigee generated (operational error, bug), the flow would now be short circuited to error handling shared flow.

Now, one of the policies in your shared error flow should be a "Raise Fault" Policy . If you are handling multiple content-types in your request,

  1. you can define multiple formats of fault through multiple Raise Fault Policies(e.g. JSON,XML,SOAP)
  2. configure a step condition for each of these policies to execute only when the content-type in the request matches . So, the Raise Fault Policy creating an XML payload would be triggered only when the content-type is application/xml or text/xml
  3. You can define the templated XML in the Raise Fault Policy (for XML content type), set the content-type in the Payload . So, for e.g. your Raise Fault Policy could appear as follows
<Set>    
 <Payload contentType="application/xml">        
    <error>          
       <code>{my.error.code}</code>          
       <message>{my.error.message}</message>          
     </error>
 </Payload>
</Set>          

Here, my.error.code and my.error.message are the apigee context variables which you may have set to include details about the error. It's perfectly fine to include string literals instead of context variables

@rmishra - Get the raise fault and actually have a it working where I send back a XML formatted response. But I also need to capture the request coming in and append the response to that request and send it back to the client. As far as I can tell there is no way to do that in a raise fault using the set payload. You are manually building XML the XML and have to include a tag for everything. I can capture the request but I need to be able to copy each element with tags. So is there anyway possible to raise a fault and set a XSL transform step so that a complete XML can be built with a request and response. I have not be able find any policy, i.e. Assign Message, Raise fault, etc where you can set that step. It does out clients no good if they receive a error response if they have no idea what the error is for.

@Rick DeckerYou can meet the requirement of correlating the request and response by inserting a "Tracking Id" in the request header, the response (even if it is an error) must carry the same tracking Id header.

BUT if you were absolutely insistent on on inserting the original request into the error structure, in the Proxy Flow (Or Preflow) store the original request into a context variable. Use the context variable and insert it into the Raise Fault XML Template. Apigee should treat the context variable as a string (even if it has XML tags) and just append the string (even though its XML) to your error template.