Question on $esc.jsonString and null input values

The documentation indicates we should escape all strings when building PUT, POST, and PATCH requests. I know this is best practice, but I'm running into a sort of race condition with it.

In my data action, I'm doing a PATCH request to Salesforce to update a Case record. Because I want the Data Action to be modular, I'm actually designing our flow so that we have a "Get Salesforce Case" data action with all the fields we use in Genesys, and the Update Salesforce Case action will take the values from the Get data action and only replace those if we need to, within the architect flow.

The actual issue is that some of these fields can be legitimately null, however, I either have a syntax issue in my Velocity template or there's a design issue with using $esc.jsonString when that string could be empty some of the time.

Here's the template I'm using. I've tried both the $ and $! notation for the variables, but the action always fails if any of the fields is legitimately null.

{
  "Subject": "$esc.jsonString($!{input.Subject})",
  "Product__c": "$esc.jsonString($!{input.Product__c})",
  "Reason": "$esc.jsonString($!{input.Reason})",
  "Lang__c": "$esc.jsonString($!{input.Lang__c})",
  "Origin": "$esc.jsonString($!{input.Origin})",
  "SuppliedPhone": "$esc.jsonString($!{input.SuppliedPhone})",
  "Supplied_Country__c": "$esc.jsonString($!{input.Supplied_Country__c})",
  "Description": "$esc.jsonString($!{input.Description})",
  "Status": "$esc.jsonString($!{input.Status})",
  "Bypass_Survey__c":$input.Bypass_Survey__c
}

When one of the fields is null, the platform throws this error. In this case, Lang__c was null as an input. I've worked around this for Description which is the most risky not to escape, from within Architect by checking IsNotSetOrEmpty and writing empty as a literal string (not ideal, though).

{
  "message": "Substitution values invalid in action config. Invocation of method 'jsonString' in  class com.inin.integrations.hedwig.data.variables.VariableVelocityEscapeTool threw exception java.lang.NullPointerException: Cannot invoke \"String.length()\" because \"input\" is null at BodyTemplate[line 5, column 20]  A common reason for this error is needing to prepend the variable with 'input.' or 'credentials.'",
  "code": "invalid.substitution",
  "status": 400,
  "messageParams": {},
  "contextId": "32c205e7-8eda-4681-befd-bcc33039c73e",
  "details": [
    {
      "errorCode": "ACTION.PROCESSING"
    }
  ],
  "errors": []
}
1 Like

Hi @plmcgrn
In this case you should be able to add null checks before calling the escape function. See the velocity docs for
CheckingForNull - VELOCITY - Apache Software Foundation. You may need to use #end to terminate the if statement

1 Like

Do you have a working example of that within Genesys? I find these templated to be syntactically frustrating to work with, and troubleshooting syntax errors even more so. You're basically saying I need to wrap every input variable in an if statement, individually, so this gets quite complex in syntax.

Does
"Lang__c": "$esc.jsonString($!{input.Lang__c})",

just become this?

#ifnutnull ($input.Lang__c)
"Lang__c": "$esc.jsonString(${input.Lang__c})",
#end

EDIT, this fails validation, for example. I opted for the #ifnotnull function instead of an if.

{ 
  #ifnotnull ($input.Subject)
  "Subject": "$esc.jsonString(${input.Subject})",
  #end
  #ifnotnull ($input.Product__c != null)
  "Product__c": "$esc.jsonString(${input.Product__c})",  
  #end
  #ifnotnull (input.Reason != null)
  "Reason": "$esc.jsonString(${input.Reason})",
  #end
  #ifnotnull ($input.Lang__c != null)
  "Lang__c": "$esc.jsonString(${input.Lang__c})",
  #end
  #ifnotnull ($input.Origin != null)
  "Origin": "$esc.jsonString($!{input.Origin})",
  #end
  #ifnotnull ($input.SuppliedPhone != null)
  "SuppliedPhone": "$esc.jsonString($!{input.SuppliedPhone})",
  #end
  #ifnotnull ($input.Supplied_Country__c != null)
  "Supplied_Country__c": "$esc.jsonString($!{input.Supplied_Country__c})",
  #end
  #ifnotnull ($input.Description != null)
  "Description": "$esc.jsonString($!{input.Description})",
  #end
  #ifnotnull ($input.Status != null)
  "Status": "$esc.jsonString($!{input.Status})",
  #end
  "Bypass_Survey__c":$input.Bypass_Survey__c
}

Error:

Template validation failed for 'config.request.requestTemplate'. Details: Encountered "#end" at validate config.request.requestTemplate[line 4, column 3] Was expecting one of: "\u001c" ... "\u001c" ... "||" ... "|" ... "(" ... ")" ... <ESCAPE_DIRECTIVE> ... "]]#" ... <WHITESPACE> ... <NEWLINE> ... <SUFFIX> ... <STRING_LITERAL> ... <INTEGER_LITERAL> ... <FLOATING_POINT_LITERAL> ... <DOT> ... "{" ... "}" ... "\\\\" ... "\\" ... <TEXT> ... <INLINE_TEXT> ... <EMPTY_INDEX> ... "{" ... "\u001c" ...

There's a working example here

If I check for nulls in Architect and set these values to an empty string instead of NOT_SET/null, will the Data Action config better handle this null scenario? The syntax for this template is giving me hives...

That sounds like it would work as well, but I can't guarantee it because I haven't tried that approach. Let us know if it works for you.

I updated the process automation workflow invoking the data action so the formula passed into the field for each is wrapped in a check for null, like this. It seems to be working, but the Data Action Performance report only shows daily breakdown, so I need to let it sit for a day (or look at interactions by hand...)

If(
	IsNotSetOrEmpty(State.CaseLang),
		"",
		State.CaseLang
)

Hi all,

First, please post an idea to Genesys Cloud Ideas Portal for $esc.jsonString to have an input of null return an output of null, instead of failing. I am assuming that this is the desired behavior.

Second, I think you should be able to see how your data action is performing within an hour. If you click on the plus next to the action's category (Generally the integration name) you will see a list of actions. Then click on the action you are monitoring. The UI will then provide a breakdown of that action's performance in 30 minute intervals.

--Jason

Hi Jason,
I posted an idea specifically on avoidance of the esc.jsonString throwing an exception if the data action's input is null. I'm being detailed on this thread to hopefully help someone else out in the future. You're welcome, future Genesys integrator!

As for reporting, I agree with you, I'd just meant that the report itself doesn't have precision for "current interval" like other views do, only "today", so I could only see stats across the day, not "since I implemented the workaround". And of course, as I type that, I realize I could've used the custom controls to start the report after my fix, I'm just too reliant on the relative filtering from muscle memory.

Checking the report today, I'm seeing 100% success rates, which is a great sign. I was seeing ~90% failure rates before putting the formulas on the Data Action inputs in Architect.

I don't know if this will help or not, but when programming in "C", C++ or C#, I can remember having to do something like this:

String str = ("" + some_possibly_null_string).ToUpper();

Having the "" provides you an empty instance of a String class so that the ToUpper() call wouldn't fail if the some_possibly_null_string were null. Perhaps you could do something similar in the template without having to have a lot of complex ifnotnull checking.

The IsNotSetOrEmpty function covers this in Genesys Cloud, thankfully, but your workaround for other languages is a fairly elegant way of brute force avoidance of nulls. Love it.

I checked in a fix for jsonString handling nulls. Assuming no surprises, it will be included in the next deploy, sometime in the next 3 weeks. Thanks for bringing this to my attention!

--Jason

1 Like

The fix for JsonString should be globally available.

Wow, nice! I have a data action change I'm planning, so I'll test this by reverting the template to the default payload and report back if there are any issues sitll.

Hi Jason,
No joy in testing this on our dev org in USW2.

  "message": "Substitution values invalid in action config. Reference $esc.jsonString(${input.Description}) evaluated to null when attempting to render at BodyTemplate[line 9, column 19]  A common reason for this error is needing to prepend the variable with 'input.' or 'credentials.'",
  "code": "invalid.substitution",
  "status": 400,

This is my request body template, and I was intentionally testing with a null description. My architect flow checks and covers that, but I'm not able to use the data action tester with nulls.

{
  "Subject": "$esc.jsonString(${input.Subject})",
  "Product__c": "$esc.jsonString(${input.Product__c})",
  "Reason": "$esc.jsonString(${input.Reason})",
  "Lang__c": "$esc.jsonString(${input.Lang__c})",
  "Origin": "$esc.jsonString(${input.Origin})",
  "SuppliedPhone": "$esc.jsonString(${input.SuppliedPhone})",
  "Supplied_Country__c": "$esc.jsonString(${input.Supplied_Country__c})",
  "Description": "$esc.jsonString(${input.Description})",
  "Status": "$esc.jsonString(${input.Status})",
  "Bypass_Survey__c":$input.Bypass_Survey__c,
  "InteractionCallIdKey__c":"$esc.jsonString(${input.InteractionCallIdKey__c})"
}

I have to use a custom template instead of the rawRequest variable because there doesn't seem to be a way to do a Salesforce Update (Patch) API call where I supply the ID to the endpoint URI path but not in the body itself.

Please open up a support ticket for this, as it seems like situations where null is reasonable is something we haven't accounted for. Having a ticket open helps get an issue like this prioritized.

As a short term hack, you could try to inject something into the raw results by having a body template along these lines:

${input.rawRequest.replaceFirst("\{", "\{ ${esc.quote}foo${esc.quote} : ${esc.quote}bar${esc.quote},")}

Basically it will put a new value into the response object immediately after the opening {

--Jason

Instead of complex syntax in the template, I'm just using IsNullOrEmpty in the architect flows that use this action, and if true, I set the value to "" instead of allowing nulls/NOT_SET.

@plmcgrn
The point though is some data actions require null as response, not an empty string.
We are not always in control or the owner of the API we are calling.
So we need to be able to send a null

@SimonBrown I'm aware. My workaround is just that, not a fix. I raised a case with our reseller to escalate to Genesys Support, so they can fix this properly. We need to be able to use esc.jsonString and pass in a null, in a way that doesn't require complex workaround code either in Architect or the data action template.