What is the ideal way to JSON.stringify in Terraform? - json

I'm working on my first Terraform project and I'm looking for the best way to stringify a JSON object. The resource I'm defining has a parameter that expects a JSON string. JSON structure is:
"document": {
"tag": "String Title",
"response": "There's a string response and perhaps a price like $[XX.XX]."
}
}
I don't think jsonencode or jsondecode do this. I could stringify them in advance but that isn't scalable in this case. I wasn't sure if I could do this with JavaScript or another language alongside Terraform, or if there's a function in HCL that will do it.

jsonencode in Terraform is exactly equivalent to JSON.stringify with only one argument in JavaScript.
For example, if you need to assign a string containing a JSON object to an argument called something_json, you could do that like this:
something_json = jsonencode({
document = {
tag = "String Title"
response = "There's a string response and perhaps a price like $[XX.XX]."
}
})
The above would set something_json to a minified version of the following JSON:
{
"document": {
"tag": "String Title",
"response": "There's a string response and perhaps a price like $[XX.XX]."
}
}
Terraform does not have an equivalent of the optional replacer and space arguments in JavaScript's JSON.stringify:
An equivalent of replacer isn't needed in Terraform because all possible values in the Terraform language have a defined JSON equivalent as described in the table in the jsonencode documentation.
space is for generating non-minified JSON; Terraform does not offer any way to do this because it is focused on generating JSON for machine consumption and so prefers to generate the most compact representation possible.

Related

Creating valid JSON for container_definitions in Terraform

I’m creating an aws_ecs_task_definition resource. Within that resource, I need a container_definitions, which needs to be a JSON string. I’d like to add multiple secrets to that definition from a list of strings; [“var1”, “var2”].
The output I need looks like:
“secrets”: [
{
“name” = “var1”,
“valueFrom” = “arn:somestuffvar1”
},
{
“name” = “var2”,
“valueFrom” = “arn:somestuffvar2”
}
],
I have tried string interpolation and templatefile, this is the section from my .tftpl
  "secrets": [
   %{ for myvar in myvars ~}
    {
      "name": "${myvar}",
     "valueFrom”: “arn:somestuff${myvar}"
    }
    %{ endfor }
  ],
The problem is the commas. the above gives me
[
{
“name” = “var1”,
“valueFrom” = “arn:somestuffvar1”
}
{
“name” = “var2”,
“valueFrom” = “arn:somestuffvar2”
}
],
with no commas between the braces, if I add a comma, then i get a trailing comma
[
{
},
{
},
],
I’ve tried a zillion syntax variations, I’ve tried jsonencode on the interpolated string, I’ve tried stripping the trailing comma. Nothing gives me valid JSON. What am I missing?
The templatefile function documentation has a section specifically about Generating JSON or YAML from a template, which explicitly discourages using string templating to try to build valid JSON from string fragments like this.
Instead, you should use the jsonencode function as the entire definition of your template, and thus let Terraform be the one to worry about generating valid JSON syntax. You then only need to worry about writing an expression that describes the data structure that remote system expects.
In your case, a template generating a JSON object with just this "secrets" property would look like this:
${jsonencode({
secrets = [
for myvar in myvars : {
name = myvar
valueFrom = "arn:somestuff${myvar}"
}
],
})}
Notice that the entire template consists of a single interpolation sequence ${ ... } and the expression inside it is one big call to the jsonencode function, with the argument describing the data structure to serialize. Therefore inside that argument we're using normal Terraform expression syntax (like you'd write in a resource argument in a .tf file) rather than the special template interpolation/repetition syntaxes. In particular, the value of "secrets" is defined using a for expression.
With your { myvars = ["var1", "var2"] } template variables, this will produce a minified version of the following JSON structure, which I'm showing with manually-added indentation and newlines just so you can read it:
{
"secrets": [
{
"name": "var1",
"valueFrom": "arn:somestuffvar1"
},
{
"name": "var2",
"valueFrom": "arn:somestuffvar2"
}
]
}
I understand that you're only showing a fragment of the template here and so the above won't include all of the other properties included in your template, but hopefully you can see how to use Terraform expression syntax to describe those properties as Terraform object attributes too, so that the overall result of this template will be a valid JSON serialization of the total data structure.

Passing json string as an input to one of the parameters of a POST request body

I need to pass a json string as a value to one parameter of a POST request body. My request body looks like this:
"parameter1":"abc",
"parameter2":"def",
"parameter3": "{\"id\":\"\",\"key1\":\"test123\",\"prod1\":{\"id\":\"\",\"key3\":\"test123\",\"key4\":\"12334\",\"key5\":\"3\",\"key6\":\"234334\"},\"prod2\":{\"id\":\"\",\"key7\":\"test234\",\"key8\":1,\"key9\":true}}\"",
"parameter4":false,
"parameter5":"ghi"
}
For parameter3 I need to be pass a string value in json format. The json file is located in my local system and is a huge file, so it would make sense if I can pass it as a jmeter variable. I tried as below:
{
"parameter1":"abc",
"parameter2":"def",
"parameter3": "${jsonObj}",
"parameter4":false,
"parameter5":"ghi"
}
after adding a JSR223 preprocessor with the code below:
import org.apache.jmeter.util.JMeterUtils;
String fileContents = new File("path to json//myJson.json").getText('UTF-8');
vars.put("fileContents",fileContents);
var deltaJson = vars.get("fileContents");
var jsonObj = JSON.parse(deltaJson);
vars.put("jsonObj", JSON.stringify(jsonObj));
But I get below error:
exceptions":{"exceptionType":"System.JSONException","exceptionMessage":"Unexpected character ('$' (code 36)): expected a valid value (number, String, array, object, 'true', 'false' or 'null') at input location [1,2]"}
Can anyone help me in resolving this issue?
There is an easier way of doing this, JMeter comes with __FileToString() function so you can achieve the same much faster and without having to do any scripting
Something like:
{
"parameter1": "abc",
"parameter2": "def",
"parameter3": ${__FileToString(path to json//myJson.json,UTF-8,jsonObj)},
"parameter4": false,
"parameter5": "ghi"
}
Also be aware of the following facts:
the recommended language for using in JSR223 Test Elements is Groovy as it provides the maximum performance
you seem to be using JSON object which cannot be used outside of the browser context therefore your code fails to generate proper JSON hence your request fails as you're passing ${jsonObj} as it is, the substitution doesn't happen, you can look to jmeter.log file yourself and see the exact reason of your script failure

JSON Template in Lua

I have a JSON object which I would like to templatize in lua. For example:
{
"type":"email",
"version":"1.0",
"account":"%emailId%"
}
I would like to substitute the %emailId% with a list of e-mail ids. Is there a templatization support for JSON in lua?
No, there is no built-in support for either JSON or templating in the core Lua language or libraries. There are a number of JSON modules available, but I'm not sure whether any of them have template support. You might have to write a templating function yourself, but it probably won't be too hard - it's just a matter of iterating over all the string values with the JSON module and using string.gsub on them.
Though it isn't intended for JSON you can use lua-resty-template.
user.json:
{ "user": "{{username}}" }
lua-code:
local template = require "resty.template"
local result = template.compile("user.json")({ username = "someone" })
print(result);
result:
{ "user": "someone" }

How do I programmatically create JSON in XQuery in MarkLogic?

I need to build up a JSON node in XQuery in MarkLogic. I know that I can use xdmp:unquote() to parse from a string into a node(). However, I’d like to build the JSON programmatically, without ugly string concatenation. I can use computed element constructors to build XML nodes in XQuery. Is there something similar for JSON nodes?
JSON is implemented in MarkLogic as an extension to the XML data model. MarkLogic 8 introduces object-node, array-node, number-node, boolean-node, and null-node tests and constructors. Thus, in XQuery you can build JSON with computed constructors, just like you would with XML. For example,
object-node {
"key" || fn:string(xdmp:random(100)): array-node { 1, 2, 3 },
"another": object-node { "child": text {'asdf'} },
"lastButNotLeast": boolean-node { fn:true() }
}
will create the JSON,
{
"key47": [1, 2, 3],
"another": {
"child": "asdf"
},
"lastButNotLeast": true
}
Aside: In JavaScript you can build JSON-like structures as JavaScript objects using JavaScript syntax. You can convert a JavaScript object into a JSON node using xdmp.toJSON(). Most builtin functions that require a JSON node, however, will do this conversion automatically, such as xdmp.documentInsert().

Jmeter Xpath Extractor JSON

I'm trying to extract the parameter roomNo from the following JSON with JMETER XPATH Extractor:
*/
{
"categoryCode": ["I4"],
"Response": {
"class": "example",
"availables": {
"available": [
{
"Desc": " Middle",
"roomNo": "5049"
},
{
"Desc": " Middle",
"roomNo": "5062"
}
],
"class": "test"
},
"advisoryInfo": null
},
"storeId": "10251"
}
*/
i use the following expression with no success:
/Response/availables/available[0]/roomNo
is the expression wrong?
UPDATE:
i'm try to use the plugins JSON PATH EXTRATCTOR. i tryied the following queries with no success:
$...available[0]
$.Response.availables.available..roomNo[0]
$.Response.availables.available[0].roomNo
UPDATE1:
one more consideration: the ajax response I recieve starts with */, is it possible this creates troubles with JSON EXTRACTOR? i see the response through view Results Tree
UPDATE2:
i try the following approach:
ajax request followed by bash extractor, followed by json extractor but it is still not working
in bash extractor i did as suggested using the following strings
String temp = new String(prev.getResponseDataAsString());
prev.setResponseData(temp.replaceAll("\*/","").getBytes());
some more question:
is it possible to see the result of bash extractor?
should i declare before json extractor that it should use temp variable? how?
I'm afraid XPath Extractor won't let you parsing JSON.
You'll need JSONPath Extractor available via JMeter Plugins (you need Extras with Libs Set).
In your case relevant JSONPath query will look like:
$.Response.availables.available..roomNo[0]
Check out Using the XPath Extractor in JMeter guide (scroll down to Parsing JSON) for more information and XPath to JSONPath mappings table.
Hope this helps.
UPD. You can use Beanshell Post Processor to get rid of your */ bits, in that case JSONPath should work fine. Beanshell PostProcessor code:
String temp = new String(prev.getResponseDataAsString());
prev.setResponseData(temp.replaceAll("\\*/","").getBytes());
Make sure that Beanshell Post Processor goes before JSONPath Extractor.