Assigning a JSON to a variable using assign message.

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}"}
1 13 10.3K
13 REPLIES 13

sidd-harth
Participant V

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"
}

Hi @Siddharth Barahalikar

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.

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.

@Dino-at-Google

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>