Technical Articles
SAP API Management – API Proxy Troubleshooting Technique
API Debugger is an handy tool to troubleshoot API Proxy. It enables to probe through the details of each step for a live traffic flowing through the API proxy. SAP Help document has adequate information on how to use this tool (so I would skip this in the blog).
Although the debugger is useful, I had use case that made me wish to see request and response payloads, headers, target URL etc in a single place instead of toggling around various policy steps (and still can’t see payload). So in this blog I want to show how I worked around this to access payload and other information using predefined variables of SAP API Management.
Implementation
SAP API Management has a long list of variables that has read/write/both permission in proxy flow within a defined scope. We can use JavaScript / Assignmessage policy to read these variables(only required ones) in the target response or error flow to help during troubleshooting. It’s advisable to use this policy only when required and otherwise disable or remove it from execution flow.
Lets now see how to built it.
Step -1 :
Create a javascript file “debugHelper.js” with below code snippet.
//Array Variables containing list of variables to be read
var reqvars = ["request.url", "request.verb", "request.headers.names", "request.queryparams.names", "request.querystring", "request.content", "request.formparams.names", "request.formstring"];
var resvars = ["target.host", "target.ip", "target.port", "response.status.code", "response.reason.phrase", "response.headers.names", "response.formparams.names", "response.content"];
var errvars = ["error.state", "error.status.code", "error.reason.phrase", "error.message", "error.content"];
//Function to Read Request Variables
function getreqVars(reqvars) {
for (i = 0; i < reqvars.length; i++) {
var tem = context.getVariable(reqvars[i]);
if (reqvars[i] == "request.headers.names" && tem != null) {
var hed = tem.toString().replace("[", "").replace("]", "");
var hed_arr = hed.split(",");
for (j = 0; j < hed_arr.length; j++)
context.getVariable("request.header." + hed_arr[j].toString().trim() + ".values");
}
if (reqvars[i] == "request.formparams.names" && tem != null) {
var form = tem.toString().replace("[", "").replace("]", "");
var form_arr = form.split(",");
for (j = 0; j < form_arr.length; j++)
context.getVariable("request.formparam." + form_arr[j].toString().trim() + ".values");
}
if (reqvars[i] == "request.queryparams.names" && tem != null) {
var qry = tem.toString().replace("[", "").replace("]", "");
var qry_arr = qry.split(",");
for (j = 0; j < qry_arr.length; j++)
context.getVariable("request.queryparam." + qry_arr[j].toString().trim() + ".values");
}
}
}
//Function to Read Response Variables
function getresVars(resvars) {
for (i = 0; i < resvars.length; i++) {
var tem = context.getVariable(resvars[i]);
if (resvars[i] == "response.headers.names" && tem != null) {
var hed = tem.toString().replace("[", "").replace("]", "");
var hed_arr = hed.split(",");
for (j = 0; j < hed_arr.length; j++)
context.getVariable("response.header." + hed_arr[j].toString().trim() + ".values");
}
if (resvars[i] == "response.formparams.names" && tem != null) {
var form = tem.toString().replace("[", "").replace("]", "");
var form_arr = form.split(",");
for (j = 0; j < form_arr.length; j++)
context.getVariable("response.formparam." + form_arr[j].toString().trim() + ".values");
}
}
}
//Function to Read Error Variables
function geterrVars(errvars) {
for (i = 0; i < errvars.length; i++) {
var tem = context.getVariable(errvars[i]);
}
}
getreqVars(reqvars);
getresVars(resvars);
geterrVars(errvars);
Note: I have tried to make this javascript configurable to add or remove variables for ease of implantation.
Optionally you can use AssignMessage policy for reading variables. I preferred to use JavaScript to read multiple variables, however used AssignMessage to read one or few variable. Below is the code snippet to read only response content.
<!-- 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'>
<AssignVariable>
<Name>sapapim.content</Name>
<Ref>response.content</Ref>
</AssignVariable>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<AssignTo createNew="false" type="response">response</AssignTo>
</AssignMessage>
Step -2 :
Create a javascript policy and assign it to Target Endpoint preflow.
Add below code snippet to bind javascript source code and policy.
<!-- this policy allows us to execute java script code during execution of an API Proxy -->
<Javascript async="false" continueOnError="false" enabled="true" timeLimit="200" xmlns='http://www.sap.com/apimgmt'>
<!-- contains the name of the main code file -->
<ResourceURL>jsc://debugHelper.js</ResourceURL>
</Javascript>
Above two steps has added debugHelper to response flow. Next step are to add debugHelper policy to error flow using fault handling. Please read this blog to know more about fault handling.
Step -3 :
Return to Proxy Overview Main Screen and hit Export from Top right corner.
Step – 4 :
Unzip the file and Open APITargetEndPoint\default.xml in a text editor of your choice.
Insert below <defaultFaultRule> code between <faultRules/> and <preFlow> to execute debugHelper policy.
<defaultFaultRule>
<name>defaultfaultRule</name>
<alwaysEnforce>true</alwaysEnforce>
<steps>
<step>
<policy_name>debugHelper</policy_name>
<condition> </condition>
<sequence>1</sequence>
</step>
</steps>
</defaultFaultRule>
Step – 5 :
Zip the API Proxy Folder and return to Develop API main screen. Import the ZIP file by choosing Import API.
Debug Result
Choose the javscript policy in the response flow to see the flow variables read from runtime.
Success Scenario: Variable read using policy in Target Response PreFlow.
Error Scenario: Variable read using policy in Target Endpoint defaultFaultFlow.
Since a few days the icons of the flow trace have been replaced with squares. Anyone with the same problems?