Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

ExtractVariables Policy Returns Array Even with index="0" — Nested JSONPath Filtering Issue

Issue Summary:
I'm using the ExtractVariables policy in Apigee X to extract values from a nested JSON structure using JSONPath with filters. Even when I use index="0" in the <Variable> tag, Apigee still returns the result as an array (e.g., ["Value1"]) instead of a single string ("Value1").

Sample JSON:

 

{
  "fieldA": "DateTime",
  "fieldB": "DateTime",
  "productType": [
    {
      "fieldC": "DateTime",
      "fieldD": "DateTime",
      "extensions": [
        { "key": "Key1", "value": "Value1" },
        { "key": "Key2", "value": "Value2" },
        { "key": "Key3", "value": "Value3" }
      ],
      "productInstances": [
        { "code": "code1", "url": "https://url/1" },
        { "code": "code2", "url": "https://url/2" }
      ]
    }
  ]
}

 

I want to extract the value corresponding to "key": "Key1" from the extensions array using the following policy:

 

<ExtractVariables name="Extract-Key1">
    <Source>response.content</Source>
    <JSONPayload>
        <Variable name="key1Value" index="0">
            <JSONPath>$.productType[*].extensions[?(@.key == 'Key1')].value</JSONPath>
        </Variable>
    </JSONPayload>
</ExtractVariables>

 

What I Get:

Even with index="0", the variable key1Value is set to:

 

["Value1"]

 

I expect it to be just "Value1".

Am I missing something or is this the expected behavior in Apigee X?

Any insights on how to achieve this would be greatly appreciated!

CC: @amitkhosla 

 

Solved Solved
2 7 415
2 ACCEPTED SOLUTIONS

Hi,

The array formatting is a result of using a Filter with jsonpath. This is the standard behavior of jsonpath when using a filter, use of a filter always results in an array. However, there is an optional parameter that can be set in for the formal jsonpath function which is array=true|false. 

To access the optional parameter in Apigee, the full jsonpath function must be used in a message template structure... see: 

Therefore an example that pulls the needed value, "Value1" from the provided example payload could look like the following using the AssignMessage -> SetVariable approach (note: I'm using the Request payload)

Note the false parameter at the end of jsonpath(path, flow variable, array?)

<AssignMessage continueOnError="false" enabled="true" name="AM-1">
<DisplayName>AM-1</DisplayName>
<Properties/>
<AssignVariable>
<Name>my-extracted-value</Name>
<Template>{jsonPath($.productType[*].extensions[?(@.key == 'Key1')].value,request.content,false)}</Template>
</AssignVariable>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>

 

View solution in original post

Yes, there is a trick that often works within Apigee. This works really well with regex expressions and it works for the jsonpath. What you do is build the path in another variable. Then use the variable that has the constructed path in it. 

In this example, I pull 2 values from the example json. The original value for Key1 is still being pulled. I have added a second extraction that pulls the value for Key2 using the name "Key2" to dynamically build the json path.

<AssignMessage continueOnError="false" enabled="true" name="AM-1">
<DisplayName>AM-1</DisplayName>
<Properties/>

<!-- this could be provided by an existing variable... just setting it here for a test -->
<AssignVariable>
<Name>value-to-search-for</Name>
<Value>Key2</Value>
</AssignVariable>

<!-- Dynamically build the json path to use -->
<
AssignVariable>
<Name>json-path-to-use</Name>
<Template>$.productType[*].extensions[?(@.key == '{value-to-search-for}')].value</Template>
</AssignVariable>

<AssignVariable>
<Name>dynamically-extracted-value</Name>
<Template>{jsonPath(json-path-to-use,request.content,false)}</Template>
</AssignVariable>

<!-- this is the previous lookup -->
<AssignVariable>
<Name>my-extracted-value</Name>
<Template>{jsonPath($.productType[*].extensions[?(@.key == 'Key1')].value,request.content,false)}</Template>
</AssignVariable>

<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
 
.
.

View solution in original post

7 REPLIES 7