null checking context variables results in com.apigee.flow.Variables@XXXXX

This morning my null condition checks were working correctly but for some reason Apigee is now returning an object address instead of null. 

I populate a context variable using the ExtractVariables policy from a SOAP request:

 

 

<ExtractVariables async="false" continueOnError="false" enabled="true" name="EXV-ExtractCredentials">
    <DisplayName>EXV-ExtractCredentials</DisplayName>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <Source clearPayload="false">request</Source>
    <XMLPayload stopPayloadProcessing="false">
        <Namespaces>
            <Namespace prefix="soapenv">http://schemas.xmlsoap.org/soap/envelope/</Namespace>
            <Namespace prefix="log">http://logon/logonrequest</Namespace>
        </Namespaces>
        <Variable name="client_id" type="string">
            <XPath>/soapenv:Envelope/soapenv:Body/log:logonRequest/clientId/text()</XPath>
        </Variable>
        <Variable name="flow.client_id" type="string">
            <XPath>/soapenv:Envelope/soapenv:Body/log:logonRequest/clientId/text()</XPath>
        </Variable>
        <Variable name="client_secret" type="string">
            <XPath>/soapenv:Envelope/soapenv:Body/log:logonRequest/clientSecret/text()</XPath>
        </Variable>
    </XMLPayload>
</ExtractVariables>

 

 

With or without the "IgnoreUnresolvedVariables" set to true or false this is still happening. 

My condition within the flow is:

 

 

        <Step>
            <Name>ASM-SetInvalidClientIdOrSecretResponse</Name>
            <Condition>(client_id notequals null AND client_secret notequals null</Condition>
        </Step>
        <Step>
            <Name>ASM-SetMissingClientIdResponse</Name>
            <Condition>(client_id equals null AND client_secret notequals null)</Condition>
        </Step>

 

 

I resorted to using a javascript policy to try and check if I was doing something wrong:

 

 

function isPopulated(fieldName) {
    var fieldValue = context.getVariable(fieldName);
    var hasContent = false;
    if (fieldValue) {
        hasContent = true;
    }
    print(fieldName + " has content " + hasContent + " (" + fieldValue + ")");
    return hasContent;
}

isPopulated("client_id");
isPopulated("client_secret");
isPopulated("monkey");

 

 

Passing in an empty tag <clientId></clientId> or not passing the element at all results in the same output from the javascript&colon;

 

 

client_id has content true (com.apigee.flow.Variables@18c0c64d)

client_secret has content true (CLIENTSECRET)

monkey has content false (null)

 

 

I added the additional variable to show that a variable that is not extracted using a policy is showing as null and no content.

Is there anything within Apigee that can be configured to return this address or is there a fault within the Apigee environment causing the issue? As I stated this was working earlier in the day and previously. I was just going to add empty checks for when the element is passed empty rather than not passed at all.

0 2 1,934
2 REPLIES 2

That sounds frustrating. 

There are two tricky things to navigate here. 

One is the ExtractVariables, with the XPath, and the XML namespaces. The other is the logical conditions testing the values. 

First, in your flow, you showed this: 

 

        <Step>
            <Name>ASM-SetInvalidClientIdOrSecretResponse</Name>
            <Condition>(client_id notequals null AND client_secret notequals null</Condition>
        </Step>
 

 

Judging from the name of the policy, you want that to occur when either the client_id OR the client_secret IS null.  The correct logical condition for that would be

 

<Condition>client_id is null OR client_secret is null</Condition>

 

The variables client_id and client_secret will be null when the elements designated by your XPath are not present in the document. I guess you might also want to handle the case in which the clientId or the clientSecret is blank. In other words, when the elements are present, but the text content of those elements is empty. The ExtractVariables policy does not treat that condition differently from "elements not present". So you can use the same condition (as above) testing for null, to check for either "not present" or "present and empty".


The second thing: the XPath and the namespaces. The ExtractVariables policy configuration that you posted was a little garbled. I could not tell what you were using for the namespace corresponding to the"log" prefix. But, let me make some comments on XML namespaces and xpath. If your original XML is shaped like this:

 

<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'
                     xmlns:log='urn:F79C8D79-8CAD-4499-BD83-341E40BC5EAA'>
  <soap:Body>
    <log:logonRequest>
      <!-- clientId and clientSecret, having no prefix, are in the default
           namespace for this node, which is the empty namespace! -->
      <clientId>ABCDEFG</clientId>
      <clientSecret>1234567890</clientSecret>
    </log:logonRequest>
  </soap:Body>
</soap:Envelope>

 

...then, assuming s refers to the soap namespace and log refers to the log namespace, you can reach clientId element via this xpath:

 

/s:Envelope/s:Body/log:logonRequest/clientId/text()

 

But if your original soap document looks like this: 

 

<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>
  <soap:Body>
    <logonRequest xmlns='urn:F79C8D79-8CAD-4499-BD83-341E40BC5EAA'>
      <!-- In this case, clientId and clientSecret use the default namespace for
           this node, which is given with the xmlns= attribute on the parent. -->
      <clientId>ABCDEFG</clientId>
      <clientSecret>1234567890</clientSecret>
    </logonRequest>
  </soap:Body>
</soap:Envelope>

 

or this:

 

<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'
               xmlns:log='urn:F79C8D79-8CAD-4499-BD83-341E40BC5EAA'>
  <soap:Body>
    <log:logonRequest>
      <!-- In this case, clientId and clientSecret use the log namespace. -->
      <log:clientId>ABCDEFG</log:clientId>
      <log:clientSecret>1234567890</log:clientSecret>
    </log:logonRequest>
  </soap:Body>
</soap:Envelope>

 

...which is equivalent, then you need a slightly different xpath.  like this: 

 

/s:Envelope/s:Body/log:logonRequest/log:clientId/text()

 

I have a working API proxy that demonstrates some of this stuff. sorry, no README but you should be able to see the test requests you can make by inspecting the proxyendpoint. 

 

The main issue I am having is that Apigee is now returning "com.apigee.flow.Variables" instead of null when I have tried to extract a variable. In the morning this was working as expected but in the afternoon the Apigee platform started returning this object reference and then was stating that it was not null. The trace showed that the variable was not read or assigned when not provided in the SOAP packet. 

You are correct that I wanted to cater for the empty scenario as well as the null scenario and that was the change I was about to start looking at but I ended up facing this issue.

The extraction of variables I am clear on and the XPath I use retrieves the correct content.