Technical Articles
SAP API Management – Handling Faults using FaultRules and DefaultFaultRule
Introduction
An API proxy could encounter many error conditions when servicing an request. These error occurs when a policy could not do what it was designed to do. In this blog we will see how to use FaultRules and DefaultFaultRule to implement a custom fault handling branch for such errors.
By default SAP API Management returns an Error code (HTTP Status) and fault message to the client application upon error. The Error and HTTP status code are documented in help.sap document for every policy. Below is an example for Verify API Key policy.
The default error message may sound mysterious at times to the consumers. So it’s a good practice to customize the error message and enrich it with information to resolve error and also return custom Header or HTTP Status code if required. Some use cases may also require execution of sequence of policy upon error {Eg. Log error and Return Custom Message}
The custom HTTP code and/or custom message can be raised using Raise Fault Policy however a common error handling pattern can only be implemented using FaultRules and DefaultFaultRule.
FaultRules and DefaultFaultRule
When an API proxy encounters error it exits the normal processing pipeline and enters into error state. In error state the API Proxy checks for FaultRules and DefaultFaultRule in the same order for execution.
- FaultRules – Contains the logic to trigger custom error messages (and other policies) based on specific conditions
- DefaultFaultRule – Contains the logic to trigger custom error messages (and other policies) when no FaultRule is executed or AlwaysEnforce element is set to true.
Important Note:
- An API Proxy enters error state only when continueOnError attribute is set to false on policy or when Raise Fault Policy is executed.
- FaultRule is evaluated bottom to top in Proxy Endpoint and top to bottom in Target Endpoint.
- Only the first matching FaultRule is executed.
Implementation
Lets take below simple scenario to exercise Fault Handling.
The proxy has two policy
- Verify API key policy (checkAPIKey) – Check if the request has a valid API Key in Header.
- Basic Authentication policy (decodeBasicCreds) – Decodes and read user name and password from Authorization Header
Without any Fault Handling in-place the API returns below error.
Case 1 : No API Key
Case 2 : Invalid API Key
Case 3 : Valid API Key without Basic Authorization
Now lets move on to include Fault Handling into the Proxy flow.
Step – 1 :
Create an Assign Message Policy to generate response for “FailedToResolveAPIKey” error code [Case-1].
<!-- This policy can be used to create or modify the standard HTTP request and response messages -->
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
<Set>
<Payload contentType="application/json" variablePrefix="@" variableSuffix="#">
{
"Cause":"Request sent without API Key",
"Resolution" : "Add APIKey Header parameter with valid API Key"
}
</Payload>
<StatusCode>911</StatusCode>
<ReasonPhrase>Request Missing API Key</ReasonPhrase>
</Set>
<Add>
<Headers>
<Header name="APIKey">No API key</Header>
</Headers>
</Add>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
Step – 2 :
With “NoAPIKeyError” Policy selected in Flow Editor, Click Delete. This would remove the Policy from the Flow sequence(only), however it will remain in the Proxy Resource (Created Policies) to be used in Fault Rule [Step – 5].
Step – 3 :
Repeat step 1 & 2 to create Assign Message Policy for other two error types and default error. Below is the code Snippet.
InvalidAPIKeyError
<!-- This policy can be used to create or modify the standard HTTP request and response messages -->
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
<Set>
<Payload contentType="application/json" variablePrefix="@" variableSuffix="#">
{
"Cause":"Request contain invlaid API Key",
"Resolution" : "Inser valid APIKey in Header"
}
</Payload>
<StatusCode>911</StatusCode>
<ReasonPhrase>Invalid API Key</ReasonPhrase>
</Set>
<Add>
<Headers>
<Header name="APIKey">Invalid API key</Header>
</Headers>
</Add>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
BasicAuthMissing
<!-- This policy can be used to create or modify the standard HTTP request and response messages -->
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
<Set>
<Payload contentType="application/json" variablePrefix="@" variableSuffix="#">
{
"Cause":"Authorization Header Missing",
"Resolution" : "Add Basic Authentication to Request Message"
}
</Payload>
<StatusCode>911</StatusCode>
<ReasonPhrase>Missing Basic Authorization</ReasonPhrase>
</Set>
<Add>
<Headers>
<Header name="BasicAuth">Missing</Header>
</Headers>
</Add>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
defaultFaultHandler
<!-- This policy can be used to create or modify the standard HTTP request and response messages -->
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
<Set>
<Payload contentType="application/json" variablePrefix="@" variableSuffix="#">
{
"Cause":"SERVICE UNAVAILABLE.",
"Resolution" : "CONTACT SUPPORT: helpdesk@abc.com."
}
</Payload>
<StatusCode>911</StatusCode>
<ReasonPhrase>SERVICE UNAVAILABLE</ReasonPhrase>
</Set>
<Add>
<Headers>
<Header name="DefaultFaultHeader">{fault.name}</Header>
</Headers>
</Add>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
After this steps the Policy Flow look the same, however 4 new Assign Message Policy are available to be used in the Flow.
Step – 4 :
Return to Proxy Overview Main Screen and hit Export from Top right corner.
Unzip the file. Read API Proxy Structure help documentation for more information about the file structure.
Step – 5 :
Open APIProxyEndPoint\default.xml in a text editor of your choice.
Lets start Adding Fault Rule to the Proxy Flow using Configuration XML {As it’s not supported in UI yet}. Insert below code replacing the existing <faultRules/> element.
<faultRules>
<faultRule>
<name>NoAPIKeyError</name>
<condition>(fault.name = "FailedToResolveAPIKey")</condition>
<steps>
<step>
<policy_name>NoAPIKeyError</policy_name>
<condition> </condition>
<sequence>1</sequence>
</step>
</steps>
</faultRule>
<faultRule>
<name>InvalidAPIKeyError</name>
<condition>(fault.name = "InvalidApiKey")</condition>
<steps>
<step>
<policy_name>InvalidAPIKeyError</policy_name>
<condition> </condition>
<sequence>1</sequence>
</step>
</steps>
</faultRule>
<faultRule>
<name>BasicAuthMissing</name>
<condition>(BasicAuthentication.decodeBasicCreds.failed = true)</condition>
<steps>
<step>
<policy_name>BasicAuthMissing</policy_name>
<condition> </condition>
<sequence>1</sequence>
</step>
</steps>
</faultRule>
</faultRules>
Note :
- faultRule/steps/step can be repeated to chain multiple policies.
- faultRule/condition can use either of [prefix].[policy_name].failed or fault.[error_name] Fault Variables.
Step – 6 :
Open APITargetEndPoint\default.xml in a text editor of your choice.
Insert <defaultFaultRule> code between <faultRules/> and <preFlow>.
<defaultFaultRule>
<name>defaultfaultRule</name>
<alwaysEnforce>true</alwaysEnforce>
<steps>
<step>
<policy_name>defaultFaultHandler</policy_name>
<condition> </condition>
<sequence>1</sequence>
</step>
</steps>
</defaultFaultRule>
Step – 7 :
Zip the API Proxy Folder and return to Develop API main screen. Import the ZIP file by choosing Import API.
The Proxy is now updated with Fault handling. Lets test!
Test Result
No API Key in Header
Invalid API Key in Header
Valid API key but no Basic credentials
Valid API key but Incorrect Basic credentials : Error returned by Target service and defaultFaultRule executed.
Hello Santhosh,
thanks for this well-written and very useful article!
Cheers,
Sven
Hello Sven,
Thank you.
Regards,
Santhosh.
Hi Sven,
Hope you are doing well.
This blog provides a different alternative to custom the responses back in the event of failures as the one you amazingly explain in the blog below:
https://blogs.sap.com/2017/04/24/sap-api-management-creating-your-own-error-codes/
What is the good practice for doing this? The one explained in your blog or the one described here by Santhosh? I guess that it depends on how reusable we want the logic to be?
Many thanks,
C.
Hi Charles,
FaultRules and DefaultFaultRule are best when the requirement is to chain a sequence of action upon error and also to implement a common error handling methods.
Raisefault is helpful for simplified use case like validating an logic (eg. error in previous policy, missing certain header/query parameter etc) and respond with custom error message and HTTP code.
Thanks,
Santhosh.
Hi Santhosh - Well articulated.
Using this approach we can ensure API Proxy's error messages can be returned in a uniform format to the calling plication.
SAP API Management should provide this feature as part of the API Proxy UI Screen otherwise it will be cumbersome to use this feature.
Anyway thanks for sharing this useful insight.
Cheers
Rajesh Pasupula
Very nice article Santhosh Kumar Vellingiri!
One question, do you know if SAP API Management accepts the creation of N Target endpoints as it is possible in Apigee? I am not able to see that option in the UI designer so I understand that needs to happen doing export and import of the API?
Many thanks for your help,
C.
Hi Charles,
Yes. It's supported by the runtime and need to be workaround through export/import.
Thanks,
Santhosh.
Hi Santhosh
What a excellent blog!I was just exploring Fault management in API M and your blog was a eye opener. Of course, makes you wonder why this is not available in the standard Policy Management UI for modelling.
If I may ask - how did you figure this out? Is there some standard document from SAP on this? Or do you need to know Apigee to get to this level of expertise?
Is there a easy way to save this as templates to apply to all your APIs or this needs to be done for each API.
Once again, excellent blog.
Regards
Bhavesh
Hi Bhavesh,
Thanks for your comment. I'm glad you found it informative.
Yes not having it in UI for modelling make it cumbersome. May be it's in SAP road-map and that could also be the reason why the details are not documented in SAP help portal.
My knowledge in applying this was purely from Apigee basics and Trial and Error method.
Policy templates is not helpful either for fault-rule configuration. It so far works only for pre, post and conditional flows. However Policy templates at least copies the policies to the proxy artifact.
Thanks,
Santhosh
Hi Santosh, Good Blog! Time flew by. Its more than 18 months, still it is not available in UI.
Hi Kumar
Good blog! I need return detail error message from backend server to consumer and ignore other content in the response when 40* happen. In the assign message policy I tried below code. But it failed to get the detail error message value. May u know how to access original report content in a assign message policy?