Hi,
How can I assign a variable using assign message with a JSON with apigee flow variable as JSON attributevalue . I want my variable to be assigned with below JSON where JSON attribute values are flow variables.
{"system_timestamp":"{system.time.year}-{system.time.month}-{system.time.day}T{system.time.hour}:{system.time.minute}:{system.time.second}.{system.time.millisecond}Z", "TransactionId":"{request.header.TransactionId}"}
Hi @Krish, this can be done in multiple ways using JS/Assign Message. I have used Assign Message policy, do have a look and modify the logic/config as required.
Method 1 -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <AssignMessage async="false" continueOnError="false" enabled="true" name="Assign-Message-1"> <DisplayName>Assign Message-1</DisplayName> <Properties/> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> <Set> <Payload contentType="application/json" variablePrefix="%" variableSuffix="#"> { "system_timestamp": "%system.time.year#-%system.time.month#-%system.time.day#T%system.time.hour#:%system.time.minute#:%system.time.second#.%system.time.millisecond#Z", "TransactionId": "%request.header.TransactionId#" } </Payload> </Set> <AssignVariable> <Name>final-variable</Name> <Ref>message.content</Ref> </AssignVariable> </AssignMessage>
Method 2 -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <AssignMessage async="false" continueOnError="false" enabled="true" name="Assign-Message-1"> <DisplayName>Assign Message-1</DisplayName> <Properties/> <AssignVariable> <Name>TransactionId</Name> <Ref>request.header.TransactionId</Ref> <Value>some-static-value</Value> </AssignVariable> <AssignVariable> <Name>year</Name> <Ref>system.time.year</Ref> </AssignVariable> <AssignVariable> <Name>month</Name> <Ref>system.time.month</Ref> </AssignVariable> <AssignVariable> <Name>day</Name> <Ref>system.time.day</Ref> </AssignVariable> <AssignVariable> <Name>hour</Name> <Ref>system.time.hour</Ref> </AssignVariable> <AssignVariable> <Name>minute</Name> <Ref>system.time.minute</Ref> </AssignVariable> <AssignVariable> <Name>second</Name> <Ref>second</Ref> </AssignVariable> <AssignVariable> <Name>millisecond</Name> <Ref>system.time.millisecond</Ref> </AssignVariable> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> <!-- using set payload to form a app/json payload ------------------> <Set> <Payload contentType="application/json" variablePrefix="%" variableSuffix="#"> { "system_timestamp": "%year#-%month#-%day#T%hour#:%minute#:%second#%millisecond#Z", "TransactionId": "%TransactionId#" } </Payload> </Set> <!-- Setting final variable ---------------------------------------> <AssignVariable> <Name>final-variable</Name> <Ref>message.content</Ref> </AssignVariable> </AssignMessage>
Final Response/Variable Output,
{ "system_timestamp": "2018-10-31T0:44:15.68Z", "TransactionId": "TRAN10790" }
Thank you for the suggestion. However, this will not work as in both the approach message content is getting changed. I don't want that. I want to keep message.content as is, just want to create a flow variable which i want to use in post client flow.
You just want this JSON as it is saved in a variable so that you can use it in MLP?
{"system_timestamp":"{system.time.year}-{system.time.month}-{system.time.day}T{system.time.hour}:{system.time.minute}:{system.time.second}.{system.time.millisecond}Z", "TransactionId":"{request.header.TransactionId}"}
Something like this?
<AssignVariable> <Name>final-variable</Name> <Value>{"system_timestamp":"{system.time.year}-{system.time.month}-{system.time.day}T{system.time.hour}:{system.time.minute}:{system.time.second}.{system.time.millisecond}Z", "TransactionId":"{request.header.TransactionId}"}</Value> </AssignVariable>
Yes. you are right. However below assign variable doesn't work as you suggested.
<AssignVariable> <Name>final-variable</Name> <Value>{"system_timestamp":"{system.time.year}-{system.time.month}-{system.time.day}T{system.time.hour}:{system.time.minute}:{system.time.second}.{system.time.millisecond}Z", "TransactionId":"{request.header.TransactionId}"}</Value> </AssignVariable>
FYI
you do not need variablePrefix='%' and so on. Since sometime in 2015, you can do this:
<Payload contentType="application/json" > { "system_timestamp": "{year}-{month}-{day}T{hour}:{minute}:{second}{millisecond}Z", "TransactionId": "{TransactionId}" } </Payload>
I personally find the curly braces to be easier on the eyes.
@Dino-at-Google yes it works without %. However it does solve my issue as I don't want to change the payload. I want to assign the json to a variable which i can use in post client flow.
Siddharth, see also this article:
ah, I understand. To avoid the problem, use createNew=true to create a NEW message, rather than over-writing the payload in the existing message. Like this:
<AssignMessage name="Assign-Message-1"> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> <AssignTo createNew='true' transport='http' type='request'>contrivedMessage</AssignTo> <Set> ...</Set> <AssignVariable> <Name>destination_variable</Name> <Ref>contrivedMessage.content</Ref> </AssignVariable> </AssignMessage>
BUT!! You don't need this any longer. You do not need to create a contrived message in order to get message template magic. You can just assign directly using the AssignVariable with the Template child element. Like this:
<AssignMessage name='AM-1'> <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables> <AssignVariable> <Name>my_destination_variable</Name> <Value>BADDBEEF</Value> <Template>{ "system_timestamp": "{year}-{month}-{day}T{hour}:{minute}:{second}{millisecond}Z", "TransactionId": "{TransactionId}" }</Template> </AssignVariable> </AssignMessage>
If you really are formatting a timestamp, there's an opportunity to improve that a little more with the message template function "timeFormatUTCMs", like this:
<AssignMessage name='AM-2'> <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables> <AssignVariable> <Name>timeFormatString1</Name> <Value>yyyyMMdd-HHmmss</Value> </AssignVariable> <AssignVariable> <Name>formatted_time</Name> <Template>{timeFormatUTCMs(timeFormatString1,system.timestamp)}</Template> </AssignVariable> <AssignVariable> <Name>my_destination_variable</Name> <Template>{ "system_timestamp": "{formatted_time}", "TransactionId": "{TransactionId}" }</Template> </AssignVariable> </AssignMessage>
See more examples here: https://github.com/DinoChiesa/ApigeeEdge-MessageTemplate-Demo
@Dino-at-Google Is <Template> tag new thing, cause I am getting validation error while saving the change. BTW I am using 18.5. However, it works in the apigee cloud.
Error Saving Revision
Error occurred while validation of bean AM-1.xml. Reason: - Schema validation failed. Cause : unexpected element (uri:"", local:"Template"). Expected elements are <{}Ref>,<{}Value>,<{}Name>. Line number : 7. Column number : 20. File name : AM-1.xml..
If <Template> is available only in the latest version(>18.5), can you suggest how can I achieve this in 18.5 apigee version?
yes, the Template element is a new thing, added only to the cloud for now.
I suppose it will be in OPDK 19.01, but I am not certain of that.
If you would like to resolve message templates like this, but in prior releases, then you can do something like this in JavaScript:
var resolveVariableReferences = (function (){ var variableNameRe = "[^ \t\n\"',/\\\\{}]+?"; // non-greedy capture var varPrefixRe = '{'; var varSuffixRe = '}'; var variableRegex = new RegExp( varPrefixRe + '(' + variableNameRe + ')' + varSuffixRe); function resolveVariableReferences(s) { var match = variableRegex.exec(s); while (match){ var variableName = match[1]; var value = context.getVariable(variableName); if (value && value !== '') { s = s.replace('{' + variableName + '}', value); } match = variableRegex.exec(s); } return s; } return resolveVariableReferences; }()); var template = "https://{endpoint}/api/User?userId={accesstoken.user.login}"; var resolvedValue = resolveVariableReferences(template); context.setVariable('resolved-template', resolvedValue);
@Dino-at-Google In your first approach, no other policy executes after assign message with createNew=true. I have added this assign message policy in fault rules and after that, I have one RF policy, the RF policy doesn't execute if I keep createNew=true, If I change to createNew=false, RF executes.
I need RF policy to execute regardless.
can you show me the flow? I understand the words but what you're describing is not making sense to me.
I found the problem. Now I am able to create a variable with a json message contrivedMessage.content using the assign message policy.
But when i use the same variable in message logging, message is not formatted as json in sumologic.
If i use
<Message>{contrivedMessage.content} </Message>
message is coming without starting {.
If i use <Message>\{contrivedMessage.content} </Message>
message is coming \{ "test":"value"}.
As it is coming with \ sumologic could not parse it as json.
Before when i used to formed the json log in the message logging policy as below, message used to come to sumo as json message.
<Message> \{"system_timestamp":"{system.time.year}"}</Message>
User | Count |
---|---|
2 | |
1 | |
1 | |
1 | |
1 |