This one is tricky. You may want to review the expected request payloads and see if there are any other possible elements you could key off of. Also, be mindful that there are limits to the cache key size. Currently, the cache key can be no larger than 2KB (2048 characters).
With all of those caveats, you have at least two possibilities. Neither are great.
Option 1. Base64 encode the request payload, then concatenate that to the query params. To do this, you first need an AssignMessage policy to convert the string to base64 using a message template.
<AssignMessage async="false" continueOnError="false" enabled="true" name="convertBodytoBase64">
<DisplayName>convertBodytoBase64</DisplayName>
<Properties/>
<AssignVariable>
<Name>base64_body</Name>
<Value>null</Value>
<Template>{encodeBase64(request.content)}</Template>
</AssignVariable>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
Then in your Response Cache policy, you can set the <CacheKey> like so:
<CacheKey>{request.queryparam.AppID}-{request.queryparam.ObjectID}-{base64_body}</CacheKey>
Option 2: Create a JSON dictionary using an array in a Javascript policy. You’ll need to know the expected payloads in advance, but if there is a short list this is viable. Keep in mind, this would also allow you to bypass the 2KB cache key limit.
First, create your object map Javascript resource file json_map.js, like so:
// sample JSON objects
var obj1 = {
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": [
"GML",
"XML"
]
},
"GlossSee": "markup"
}
}
}
}
};
var obj2 = {
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "T",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": [
"GML",
"XML"
]
},
"GlossSee": "markup"
}
}
}
}
};
// create an empty array
var req_obj_dictionary = [];
// add objects to the array
req_obj_dictionary.push(obj1);
req_obj_dictionary.push(obj2);
Then, create another Javascript resource file find_json.js, like so:
var req_obj = JSON.parse(context.getVariable("request.content"));
var match_obj = context.setVariable("json_map_index",findObjectIndex(req_obj_dictionary,req_obj));
function findObjectIndex(arr, obj) {
for (var i = 0; i < arr.length; i++) {
if (JSON.stringify(arr[i]) === JSON.stringify(obj)) {
return i.toString();
}
}
return "-1";
}
And finally, create a Javascript policy, like so:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Javascript async="false" continueOnError="false" enabled="true" timeLimit="200" name="json-obj-map">
<DisplayName>json-obj-map</DisplayName>
<Properties/>
<IncludeURL>jsc://json_map.js</IncludeURL>
<ResourceURL>jsc://find_json.js</ResourceURL>
</Javascript>
Now, you can reference the JSON objects as an index of your array when storing them as a cache key in the Response Cache policy:
{request.queryparam.AppID}-{request.queryparam.ObjectID}-{json_map_index}
Again, I want to reiterate that both options are not great. You could run into some performance bottle necks, particularly as the proxy scales to 1000s of transactions per second. I strongly encourage you perform rigorous testing so make sure the performance and behavior is aligned with your SLOs.