How can I set Values for constants into context variables, from within JavaScript?

I want to know what is the best practice for specific values that it will be to used in a few policies of all proxy.

I have this:

//get request json
var jsonObject = JSON.parse(context.getVariable('request.content')); 
//update json object - add a new key
jsonObject.guid = "sdf239hsd90fh23f";

Specific I want to get this value "sdf239hsd90fh23f", since other policity and reuse for another policities.

So, I'm thinking how to do this.

I read about KVM, but I'm not sure that the best practice will be to use for set values on JS files or AssignMessage.

In your experience ¿What is the better option?

0 6 3,862
6 REPLIES 6

Can you give a specific example of the constant and how you plan to use it?

(I'm having trouble understanding this:

"I'm not sure that the best practice will be to use for set values on JS files or AssignMessage"

)

I think what you want to to is shred the values in the JSON payload and set context variables that can be used by other policies.

This may be obvious to some, and less obvious to others: Variables that are known within the JavaScript callout are not accessible within the request flow context. For example, suppose this is the JS code:

var jsonObject = { "foo" : "bar" };

The name "jsonObject" is known only within the scope of the JavaScript execution. It is not accessible in an AssignMessage policy, or any other policy, or any Conditions that follow the JavaScript step.

There IS a way to read and write context variables from within the logic for a JavaScript step - that is with context.getVariable() and context.setVariable().

In the simplest case, suppose you want to set a guid, from within the JavaScript step, and have that guid be accessible to Conditions, or future AssignMessage policies. You can do this:

var guid = "4F825E81-C498-4943-9C1F-3578DE3E70C5";
context.setVariable("my.guid.variable", guid);

And subsequent policies will be able to reference the variable named "my.guid.variable" to see that string.

Maybe your requirement is a bit more advanced. Maybe you'd like to extract every field in any particular JSON payload and "export" that to a context variable. So, for this JSON:

{ "foo" : "bar", "id" :7, "ready" : true }

You might want three context variables representing each one.

This is also possible with a recursive function applied over the json graph. It might look something like this:

 var jsonObject = JSON.parse(context.getVariable('request.content')); 
 walkObj(jsonObject,
         function(name, value) {
             context.setVariable(name, value);
         });

Basically that says "for every property in the json, set a context variable." But what is this "walkObj" function? it's basically an object analogue to Array.prototype.forEach . Here's what it looks like:

// walkObj.js 
  var what = Object.prototype.toString;
  function walkObj(obj, path, fn) {
    if ( ! fn && typeof path == 'function') {
      fn = path;
      path = 'json';
    }
    var wo = what.call(obj), p;
    path = path || '';
    if (wo == "[object Object]") {
      Object.keys(obj).forEach(function(key){
        var item = obj[key], w = what.call(item);
        var pathelts = path.split('.');
        pathelts.push(key);
        var newpath = pathelts.join('.');
        if (w == "[object Object]" || w == "[object Array]") {
          walkObj(item, newpath, fn);
        }
        else {
          fn(newpath, item);
        }
      });
    }
    else if (wo == "[object Array]") {
      obj.forEach(function(item, ix){
        var w = what.call(item);
        var pathelts = path.split('.');
        pathelts.push('['+ix+']');
        var newpath = pathelts.join('.');
        if (w == "[object Object]" || w == "[object Array]") {
          walkObj(item, newpath, fn);
        }
        else {
          fn(newpath, item);
        }
      });
    }
    else {
      var msg  = "Unknown object to covert: " + wo + "("+ JSON.stringify(obj, null, 2).slice(0, 34) +")";
      //console.log(msg);
      throw {error: true, message: msg };
    }
  }

The JS policy configuration looks like this:

<Javascript name='JS-ExtractInboundRequest' timeLimit='200' >
  <Properties>
    <Property name='prefix'>json</Property>
  </Properties>
  <IncludeURL>jsc://walkObj.js</IncludeURL>
  <ResourceURL>jsc://extractInboundRequest.js</ResourceURL>
</Javascript>

Let's try it. Running that policy on the inbound payload like this:

{ "foo" : "bar", "id" :7, "ready" : true }

results in these context variables being set:

name of variable value
json.foo "bar"
json.id 7
json.ready true

You can also pass in more complex JSON payloads. For example, given this input:

{
  "name": "rooms/AAAAra-BYE/chats/qo4NQAAAAAE/messages/Ko4NQABBAE",
  "sender": {
    "name": "users/1138844348030",
    "displayName": "Dino Chiesa",
    "avatarUrl": "https://foo.bar.bam.com/-cBWaVITMntw/AAAAAAAAAAI/AAAAAAAA/hxGRhDY/photo.jpg",
    "email": "dchiesa@google.com"
  },
  "createTime": "2017-03-07T23:53:04.504207Z",
  "text": "/jira MGMT-3909"
}

The resulting context variables are:

variable name value
json.name rooms/AAAAra-BYE/chats/qo4NQAAAAAE/messages/Ko4NQABBAE
json.sender.name users/1138844348030
json.sender.displayName Dino Chiesa
json.sender.avatarUrl https://foo.bar.bam.com/-cBWaVITMntw/AAAAAAAAAAI/AAAAAAAA/hxGRhDY/photo.jpg
json.sender.email dchiesa@google.com
json.createTime 2017-03-07T23:53:04.504207Z
json.text /jira MGMT-3909

Please find attached a working example proxy. Import and deploy it and you can see it working.

extract-json-apiproxy.zip

Thank you Dino.

I asked for the opposite, when you have some values in other policities and you want to use in file Javascript code, without the values being contained in the payload.

With

context.setVariable(name, value);

You put the value in all context and you can use for others policities, but this values are constants that will added to request and its not contain in the payload.

¿Is posible?


Cheers.

Ah, I see. Yes, it is possible.

Like context.setVariable(), there is context.getVariable().

Suppose you have a KeyValueMapOperations policy that retrieves some information from the Key-Value Map (persistent store in Apigee Edge). Maybe the policy looks like this:

<KeyValueMapOperations name='KVM-Get-JiraCreds' mapIdentifier='secrets1'>
  <Scope>environment</Scope>
  <Get assignTo='private.jira_username'>
    <Key>
      <Parameter>jiraUser</Parameter>
    </Key>
  </Get>
  <Get assignTo='private.jira_password'>
    <Key>
      <Parameter>jiraPwd</Parameter>
    </Key>
  </Get>
</KeyValueMapOperations>

The result of this is to load into the request context, two new variables, with names "private.jira_username" and "private.jira_password".

After that policy, I can insert a JavaScript policy that accesses this information, in this way:

var username = context.getVariable('private.jira_username');
var password = context.getVariable('private.jira_password'); 
...

The logic in the JS could continue, and embed that information into the request payload, with something like this:

var payload = JSON.parse(context.getVariable('request.content'));
// introduce new property in the JSON hash
payload.auth = {
 username : username,
 password : password
};
// now put that JS variable into the context
context.setVariable('request.content', JSON.stringify(payload)); 

Thaks a lot Dino.

I have another doubt...

In some case I used the policy Extract Variables for make the payload to send endpoint.

The name of variable and the value (JSONPath) was made with elements from request. In this case,

How can add variables and values from a KVM?

Is correct use Extract Variable instead Javascript code?

There is the code for Extract Variable.

  <DisplayName>Extract Variables-JSON</DisplayName>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <JSONPayload>
  <Variable name="biller_id">
  <JSONPath>$.biller_id</JSONPath>
  </Variable>
  <Variable name="external_id">
  <JSONPath>$.external_id</JSONPath>
  </Variable>
  <Variable name="currencyCode">
  <JSONPath>$.currencyCode</JSONPath>
  </Variable>
  <Variable name="amount">
  <JSONPath>$.amount</JSONPath>
  </Variable>
  <Variable name="account_number">
  <JSONPath>$.account_number</JSONPath>
  </Variable>
  <Variable name="payment_type">
  <JSONPath>$.payment_type</JSONPath>
  </Variable>
  <Variable name="accounting_date">
  <JSONPath>$.accounting_date</JSONPath>
  </Variable>
  </JSONPayload>
  <Source clearPayload="false">request</Source>
</ExtractVariables>



Thanks for your advices.

Hi - it seems like you have a set of new questions here.

Can you ask a new question please?

6536-ask-a-question.png

Also I don't understand "How can add variables and values from a KVM"

Add to what? What's a variable? I think there is a slight language problem. Maybe what you could do, when you post your new question, is explain with examples , what you would like to accomplish. To clarify for me.