What is the difference between context.session['hello'] = {} and context.setVaraible("hello", {})

I believe it's same & there is no difference. Is there any reason why there are two ways to do same ? Any difference between them ?

$$$REWARD$$$: If someone proves there is a difference, I will reward 50 Community Points from my own account. Any takers ?

Solved Solved
1 12 5,367
2 ACCEPTED SOLUTIONS

Not applicable

You should use context. {setVariable, getVariable }

context.session will probably be deprecated in future releases.

View solution in original post

I've used and relied on context.session before (quite a lot, actually) for what I believe to be valid use-cases.

As pointed out by Carlos, a major difference is variable types and, in the case of retrieval, how a non-existent variable will evaluate to null/undefined. In my opinion though, the fundamental difference is in what Mohammed started to share.

The scope covered by context.session versus context.[get|set]Variable() is completely different. Variables set to context.session are only available to the JavaScript policies executing in the flow and do not overlap with any of the standard variables available to the Edge runtime. In other words, neither of the following lines are valid.

context.session['request.verb']; // undefined
context.session.request.verb; // Cannot read property "verb" from undefined

There's no sharing across requests either; don't be fooled by the name "session" 🙂

Now, onto a use-case for when I have previously used context.session. Let's assume a simple proxy; with a callout for translations, some mediation/mash-up of the two responses and a final response back to the client.

  • Target request sent
  • Target response received
  • JS policy to modify the response:
    var targetResponseObj = JSON.parse(context.getVariable('response.content'));
    targetResponseObj.foo = 'awesome bar';
  • Now, we still need to make a callout and merge the two responses before responding to the client. Here are our options for the next step:
    1. Serialise the modified object and set it as a runtime flow variable for later access where it will need to be parsed again:
      var serialisedModifiedResponse = JSON.stringify(modifiedTargetResponse);
      context.setVariable('flow.modifiedTargetResponse', serialisedModifiedResponse);

      or

    2. Set the modified object to a JavaScript variable that can be picked up later, as an object. You skip serialising, the setting of the runtime flow variable and the parsing:
      context.session.modifiedTargetResponse = modifiedTargetResponse;
  • Service callout request sent
  • Service callout response received
  • JS policy to merge the two responses. Again, the options:
    1. Get the serialised modified target response from a variable, parse it, get the callout response, parse it, add the callout response and set the final client response:
      var modifiedTargetResponse = JSON.parse(context.getVariable('flow.modifiedTargetResponse'));
      var calloutResponse = JSON.parse(context.getVariable('calloutResponse.content');
      
      modifiedTargetResponse.translated = calloutResponse;
      context.setVariable('response.content', JSON.stringify(modifiedTargetResponse));

      or

    2. Get the callout response, parse it, add the modified response object and set the final client response
      var calloutResponse = JSON.parse(context.getVariable('calloutResponse.content'));
      context.session.modifiedTargetResponse.translated = calloutResponse;
      context.setVariable('response.content', JSON.stringify(context.session.modifiedTargetResponse));

The point here isn't a comparison of the amount of code, but rather, the number of times data is parsed/serialised within your flow. With large responses, avoiding these additional steps can reduce the work MPs have to do and the footprint per request. This can make a difference at high levels of traffic.

Another use-case, more relevant to slightly larger proxies, would be to abstract common JavaScript function definitions to a single place.

// you could have a "set-functions" policy
context.session.functions.padLeft = function(str, len) {...};
context.session.functions.isNaN = function(n) {...};
context.session.functions.validateEmail = function(email) {...};

// and later use these from other JS policies
context.session.functions.padLeft('pad me', 10);

We now understand why getting and setting on context.session doesn't show in the trace tool. It's the same reason you don't see anything in the trace for if(){} -- it's just executing JavaScript internally.

cc: @Anil Sagar, @Peter Johnson

View solution in original post

12 REPLIES 12

You asked about setting, not getting. But I think the most interesting difference is on the getting side, where it would affect truthiness. When the variable you are retrieving doesn't exist, context.session returns undefined while context.getVariable returns null. That's one of those weird JavaScript things that can trip you up when you're checking for the existence of something.

On the writing side, it appears that using .session doesn't show the var in the variables section of a trace. I didn't poke beyond that to see if there are oddities. I think I'd argue for context.setVariable so I could see what's happening to it in trace. ((Although the print() function works just fine with either method to dump the content to the Output from All Transactions section of trace.))

¯\_(ツ)_/¯

Thanks @Carlos Eberhardt , I believe it's due to some legacy code / backward compatibility we ended up having two different ways to store the custom values in message context flow. Looking forward to listening the story behind it from Engineering team. @arghya das Any idea ? Especially the word "session" is confusing for me when i hear in Apigee Edge Runtime context.

Hi @Anil Sagar ,

Another difference apart from one mentioned by @Carlos Eberhardt, context.setVariable creates or sets a flow variable which you can use in further step conditions. Whereas any session variable will not be available out the context of Javascript 😞

I have not tried accessing session variables through Java Callout as there is no documentation available to refer. I believe it's only available for Javascript Callouts.

Thanks @Mohammed Zuber , +1, It was on my list to verify same using ExtractVariables policy too. Will keep you guys posted.

Not applicable

You should use context. {setVariable, getVariable }

context.session will probably be deprecated in future releases.

Thank you @Peter Johnson for the information. It's helpful. @docs , @sgilson , Can we update this information in docs here / point to this article / Add a note saying "Using Context.Session is discouraged" ? Thank you.

How is the deprication going? To me it seems this whole shenanigans is essentially a flawed design and should be corrected as soon as possible. Is usage of context.session "officially" now frowned upon? If yes, it should be expressed in the manual.

I've used and relied on context.session before (quite a lot, actually) for what I believe to be valid use-cases.

As pointed out by Carlos, a major difference is variable types and, in the case of retrieval, how a non-existent variable will evaluate to null/undefined. In my opinion though, the fundamental difference is in what Mohammed started to share.

The scope covered by context.session versus context.[get|set]Variable() is completely different. Variables set to context.session are only available to the JavaScript policies executing in the flow and do not overlap with any of the standard variables available to the Edge runtime. In other words, neither of the following lines are valid.

context.session['request.verb']; // undefined
context.session.request.verb; // Cannot read property "verb" from undefined

There's no sharing across requests either; don't be fooled by the name "session" 🙂

Now, onto a use-case for when I have previously used context.session. Let's assume a simple proxy; with a callout for translations, some mediation/mash-up of the two responses and a final response back to the client.

  • Target request sent
  • Target response received
  • JS policy to modify the response:
    var targetResponseObj = JSON.parse(context.getVariable('response.content'));
    targetResponseObj.foo = 'awesome bar';
  • Now, we still need to make a callout and merge the two responses before responding to the client. Here are our options for the next step:
    1. Serialise the modified object and set it as a runtime flow variable for later access where it will need to be parsed again:
      var serialisedModifiedResponse = JSON.stringify(modifiedTargetResponse);
      context.setVariable('flow.modifiedTargetResponse', serialisedModifiedResponse);

      or

    2. Set the modified object to a JavaScript variable that can be picked up later, as an object. You skip serialising, the setting of the runtime flow variable and the parsing:
      context.session.modifiedTargetResponse = modifiedTargetResponse;
  • Service callout request sent
  • Service callout response received
  • JS policy to merge the two responses. Again, the options:
    1. Get the serialised modified target response from a variable, parse it, get the callout response, parse it, add the callout response and set the final client response:
      var modifiedTargetResponse = JSON.parse(context.getVariable('flow.modifiedTargetResponse'));
      var calloutResponse = JSON.parse(context.getVariable('calloutResponse.content');
      
      modifiedTargetResponse.translated = calloutResponse;
      context.setVariable('response.content', JSON.stringify(modifiedTargetResponse));

      or

    2. Get the callout response, parse it, add the modified response object and set the final client response
      var calloutResponse = JSON.parse(context.getVariable('calloutResponse.content'));
      context.session.modifiedTargetResponse.translated = calloutResponse;
      context.setVariable('response.content', JSON.stringify(context.session.modifiedTargetResponse));

The point here isn't a comparison of the amount of code, but rather, the number of times data is parsed/serialised within your flow. With large responses, avoiding these additional steps can reduce the work MPs have to do and the footprint per request. This can make a difference at high levels of traffic.

Another use-case, more relevant to slightly larger proxies, would be to abstract common JavaScript function definitions to a single place.

// you could have a "set-functions" policy
context.session.functions.padLeft = function(str, len) {...};
context.session.functions.isNaN = function(n) {...};
context.session.functions.validateEmail = function(email) {...};

// and later use these from other JS policies
context.session.functions.padLeft('pad me', 10);

We now understand why getting and setting on context.session doesn't show in the trace tool. It's the same reason you don't see anything in the trace for if(){} -- it's just executing JavaScript internally.

cc: @Anil Sagar, @Peter Johnson

I didn't think my answer would be so long - apologies.

Perhaps I should have shared this some other way.

Absolutely great answer @Omid Tahouri +1, As a community we always love to see more detailed answers. No need to apologies at all. Great answer again, Keep them coming !!

A note has been added to the doc. Thanks -- this is an excellent discussion.

Awesome, Thank you @wwitman , +1