VMware Cloud Community
RonPSSC
Enthusiast
Enthusiast
Jump to solution

How to parse JSON Results from NSX Manager via vRO Rest API Call ?

Hello...

Trying to access or parse nested objects/arrays from JSON output but can't seem to get passed one frustrating hurdle.. I've seen a similar posting on this but doesn't quite address my issue. Any help would be appreciated. For the record, I am a newbie. Thx.

Here's the JSON output I'm trying to access. The Objects I'm looking to enumerate in the arrays are "dataPage":"data":"name": and "dataPage":"data":"backing":"switch Obj": "objectID": I am not searching on any specific object numeric value either (I am merely trying to locate unique virtual wire names to continue building further upon in my script.  : (Note formatting may be offset).

 

{
"dataPage": {

  "pagingInfo": {
  "pageSize": 20,
  "startIndex": 0,
  "totalCount": 24,
  "sortOrderAscending": true
   },

"data": [
             {
             "objectId": "virtualwire-1",
             "objectTypeName": "VirtualWire",
             "name": "Transit-Network",
             "backing": [
                             {
                              "switch Obj": {
                                                    "objectId": "dvs-28",
                                                    },

                              }
                              ]
               },

              {
               "objectId": "virtualwire-2",
               "objectTypeName": "VirtualWire",
               "name": "Web-Tier",
                "backing": [
                                 {
                                 "switchObj": {
                                                      "objectId": "dvs-28",
                                                      },

                                  },
                                  ]
                {
                "objectId": "virtualwire-3",
                "objectTypeName": "VirtualWire",
                "name": "App-Tier",
                "backing": [
                                {
                                "switchObj": {
                                                     "objectId": "dvs-28",
                                                     },
                                 }
                                 ]
                  }
        ]

 

 

Here's the code I'm using: Error I'm getting is "Error in (Workflow:Find One TIE Gateway / Parse JSON (item1)#56) TypeError: Cannot read property "data" from undefined

 

 

var theType = "GET";

operationUrl = "/2.0/vdn/virtualwires/"

//Set up and make request/PUT

var request = restHost.createRequest(theType, operationUrl, "");
request.setHeader("Content-Type", "application/json; charset=UTF-8");
request.setHeader("Accept", "application/json");


//Log the URL
System.log("request: " + request.fullUrl);

var response = request.execute();

//log the JSON response
System.log("vdn response: " + response.contentAsString);



var wiresObject = response.contentAsString;



var items = wiresObject.dataPage.data  ("Error in (Workflow:Find One TIE Gateway / Parse JSON (item1)#56) )


//System.log("Items Output :" + items);

 

//Create Virtual Wire Index based on vWire Name

var theWireIndex;

for (i = 0; i < items.length; i++) {

var strName = items[i].name

//System.log(strName)
if (strName.indexOf(nameToFind + "-vWire") > -1) {
//System.log('the index with the string is: ' + i);
theWireIndex = i;


}

}

 

Labels (1)
0 Kudos
1 Solution

Accepted Solutions
eoinbyrne
Expert
Expert
Jump to solution

Hi there

Try this...?

//log the JSON response
System.log("vdn response: " + response.contentAsString);

// The value of 'response.contentAsString' is a 'String' type - you need to convert it to a JS 'Object' type using JSON.parse

var wiresObject = JSON.parse(response.contentAsString);

// Now you can access the content of the Object referencing the members the way you want to
var items = wiresObject.dataPage.data;

// You can also convert things back to a JSON String using this

System.log("Items Output :" + JSON.stringify(items, null, 2));

View solution in original post

7 Replies
eoinbyrne
Expert
Expert
Jump to solution

Hi there

Try this...?

//log the JSON response
System.log("vdn response: " + response.contentAsString);

// The value of 'response.contentAsString' is a 'String' type - you need to convert it to a JS 'Object' type using JSON.parse

var wiresObject = JSON.parse(response.contentAsString);

// Now you can access the content of the Object referencing the members the way you want to
var items = wiresObject.dataPage.data;

// You can also convert things back to a JSON String using this

System.log("Items Output :" + JSON.stringify(items, null, 2));

RonPSSC
Enthusiast
Enthusiast
Jump to solution

That is awesome.. It worked.. Thanks.. !! The original output appeared to look like it was still JS 'Object' type.

At the risk of appearing difficult, I've run into another snag in the last part of my script. In short, I'm trying to create a "Dynamic-type" object and return it back to vRA by "building" the Virtual Wire based on the values within the JSON.

Here's the code. I tried to apply your logic below but am getting additional "undefined" errors. For example: Error in (Workflow:Find One TIE Gateway / Parse JSON (item1)#94) TypeError: Cannot read property "backing" from undefined....Any additional help will be appreciated. Again, apologize..As a newbie, I'm plagiarizing old code..

 

var items = wiresObject.dataPage.data;

// You can also convert things back to a JSON String using this

System.log("Items Output :" + JSON.stringify(items, null, 2));

 

//Create Virtual Wire Index based on vWire Name

 var theWireIndex;

  for (i = 0; i < items.length; i++) {

  var strName = items[i].name

  //System.log(strName)
  if (strName.indexOf(nameToFind + "-vWire") > -1) {
  //System.log('the index with the string is: ' + i);
  theWireIndex = i;

   }

  }

//BUILD THE WIRENAME:


var wireName;
var part1 = "vxw";
var part2 = items[theWireIndex].backing[0].switchObj.objectId; // (TypeError: Cannot read property "backing" from undefined)
var part3 = items[theWireIndex].objectId;
var part4 = "sid"
var part5 = items[theWireIndex].vdnId
var part6 = items[theWireIndex].name


System.log(part1)
System.log(part2)
System.log(part3)
System.log(part5);
System.log(part6);

wireName = part1 + "-" + part2 + "-" + part3 + "-" + part4 + "-" + part5 + "-" + part6;

return wireName;

System.log(wireName);

 

0 Kudos
eoinbyrne
Expert
Expert
Jump to solution

Try this - I re-wrote what you had a bit so it may seem a little more complicated at first

// walk the items list and find the entry with the name we want, then return the entry
function findVWireByName(vwireName, vwireList)
{
	// iterate over the list and find the one with the name we need
	for each(var vw in vwireList)
	{
		if(vw.name.indexOf(vwireName + "-vWire") > -1)
		{
			return vw;
		}
	}
	return null;
}

// use the name building code to compute the wire name from the found item
function buildWireName(vwireObj)
{
	System.log("Computing vWire name from object - " + JSON.stringify(vwireObj, null, 2));
	
	var wireName;
	var part1 = "vxw";
	
	// check the backing data is present - the undefined you got previously might have indicated that
	// some the data was missing for some entries?
	if(vwireObj.backing != null && vwireObj.backing.length > 0)
	{
		var part2 = vwireObj.backing[0].switchObj.objectId; // (TypeError: Cannot read property "backing" from undefined)
	}
	else
	{
		// CHOICE TO BE MADE HERE! Pick one strategy to suit what you want
		
		// normally, I would throw the error to kill things fast
		//throw "Failed to build the vWire name - backing was not specified!!!"; 
		
		// The other option is return null from this function and let the caller line deal with it...
		return null;
	}
	
	var part3 = vwireObj.objectId;
	var part4 = "sid"
	
	// no field with this name on the JSON samples you gave? If you get another undefined here, this might be why
	// Use System.log(JSON.stringify(vwireObj, null, 2)) to print it to the logs so it can be inspected
	var part5 = vwireObj.vdnId
	
	var part6 = vwireObj.name

	System.log(part1)
	System.log(part2)
	System.log(part3)
	System.log(part5);
	System.log(part6);

	wireName = part1 + "-" + part2 + "-" + part3 + "-" + part4 + "-" + part5 + "-" + part6;

	System.log("Computed vWire name is " + wireName);
	return wireName;
}

var items = wiresObject.dataPage.data;

//BUILD THE WIRENAME:

// Find the wire data we need first...
var myVWireItem = findVWireByName(nameToFind, items);

// cehck if we got it
if(myVWireItem != null)
{
	// generate the name using the data we found
	var myVWireName = buildWireName(myVWireItem);
	if(myWireName != null)
	{
		System.log("vWire name is " + myVWireName);
	}
	else
	{
		System.log("Failed to compute vWire name - some data was missing?" + JSON.stringify(myVWireItem, null, 2));
	}
}
else
{
	System.log("No virtual wire found with name starting " + nameToFind);
}

 

 

I have not run this so give it a whirl and see how it goes

RonPSSC
Enthusiast
Enthusiast
Jump to solution

Hello Again;

I replied to you via PM after your last reply but you can ignore that since I believe I made a little more progress since then...Although I am grateful for the help you've provided thus far, I do run the risk of annoying you further because I need your help again. 🙄

I struggled somewhat in trying to apply your logic into my current use case over the past week or so. I think I was able to properly apply your suggestions but not entirely sure (..this is awfully new to me). Although the script is not erroring out, I'm not getting any output from the various "functions" you identified. There's a strong possibly they're not being invoked properly or at all so I'll defer to you (or anyone else) for additional help.

I've attached a file with the majority of the scripting for ease of reference.. (There's other stuff that occurs prior to this, but am having no issues there) . On that note, the JS 'Object' type input that is fed into the script at the beginning is being properly captured by the system logging and appears to be valid.

Again any additional help would be appreciated.

Thx.  Ron

0 Kudos
eoinbyrne
Expert
Expert
Jump to solution

Hi, 

Aplogies for the radio silence, I had a busy week and never got the chance to come back to you. 

Fair play getting the workflow to the stage you have, glad I was able to help a little 🙂 I think the final problem you've got might be just down to where the value of 'myVwireName' is defined - the scoping rules probably mean that where you build your return object, the value is out of scope and so will be blank/undefined. I say probably there as I've seen some cases where my understanding of scope was not reflected in the code & have since learned that there are many ways to declare a variable in JS 🙂

Anyway, technical stuff aside, can I suggest a change to your latest workflow code which might help? I think there are two ways which can solve the problem here

 

This is the first one

// Check if we got it..
if(myVWireItem != null)
{
	// SCOPE RULES CAN BE CONFUSING 🙂 - everthing inside the matching '{' and '}' braces normally only lives within that scope
	// generate the name using the data we found
	// the variable here *may* only live within the scope defined for this block
	// Two choices - this is the first approach
	var myVWireName = buildWireName(myVWireItem);
	if(myVWireName != null)
	{
		// myVWireName variable does exist here so build the return object out now with all the values we have available
		System.log("vWire name is " + myVWireName);
		//Return the following Object back to vRA
		var object = DynamicTypesManager.makeObject("TIE", "TIE Gateway",justName ,justName, new Array());

		object.setProperty("objectId", id);
		object.setProperty("GatewayName", GatewayName);
		object.setProperty("ipAddress", ipAddress);
		object.setProperty("NetworkName", myVWireName);

		// should have all values here
		resultObj = object;
	}
	else
	{
		System.log("Failed to compute vWire name - some data was missing?" + JSON.stringify(myVWireItem, null, 2));
	}
}
else
{
	System.log("No virtual wire found with name starting " + justName);
}

 

This is the second one

//Identify and Build THE WIRENAME:
// Find the wire data we need first...
var myVWireItem = findVWireByName(justName, items);

// Check if we got it..
// Define the variable OUTSIDE in the global script scope
var myVWireName;
if(myVWireItem != null)
{
	// generate the name using the data we found
	
	// now assign the 
	myVWireName = buildWireName(myVWireItem);
	if(myVWireName != null)
	{
		System.log("vWire name is " + myVWireName);	
	}
	else
	{
		System.log("Failed to compute vWire name - some data was missing?" + JSON.stringify(myVWireItem, null, 2));
		// throw an error here to avoid building a value that cannot be used
		throw "Failed to compute vWire name - cannot continue!";
	}
}
else
{
	throw "No virtual wire found with name starting - " + justName;
}

// NOTE:
// Throwing errors above means you can never get to here!

// Proceed to build the result
//Return the following Object back to vRA
var object = DynamicTypesManager.makeObject("TIE", "TIE Gateway",justName ,justName, new Array());

object.setProperty("objectId", id);
object.setProperty("GatewayName", GatewayName);
object.setProperty("ipAddress", ipAddress);
object.setProperty("NetworkName", myVWireName);

resultObj = object;

 

Can you let me know how this goes? If you have any more trouble I'm quite happy to help in any way I can

 

RonPSSC
Enthusiast
Enthusiast
Jump to solution

First off, want to thank you again for all your advice and work on this....Your commitment to helping the Community is admirable and much appreciated!

More developments to report on but to sum this up, everything you provided has been a success! The 2nd option above worked out fine as well.

As far as developments, I discovered an anomaly that quite possibly has been giving me grief since the beginning...at least in my testing environment.

Turns out the REST Request which was designed to retrieve the listing of all virtual wires was incomplete and needed to be appended with the following Query Parameter: ?startindex=0&pagesize=1024. The discovery revealed that the default output (w/o the query parameters) is limited to one (1) page only. This equates to roughly 20 virtual wires per page. My testing environment had double that amount. You would think the reverse would apply by default. Maybe an issue for the API specialists in VMware to rectify..? 😉 For info, 1024 is the maximum amount of page returns that can be specified in a request. Long story short, this would appear to explain the inconsistent results and the many "undefined" errors I was getting via the output throughout my testing.

Although this was a difficult issue to troubleshoot, in the end and much to your credit, I was able to narrow the scope and isolate the true source of the problem. After applying the query change as well as a few "other" necessary changes, the original script and code functioned as intended.

Despite what was discovered, I decided to re-engineer the entire script using all your input and methodology since there was considerably much more value! I liked the how you re-tooled the search features and incorporated a number of checks/logging at various stages, the ability to convert things to a JS 'Object' type and back to a string for further validation, and finally the introduction of the various "functions" and how to invoke them. All new processes to me which helped fast-track this issue immensely!

Suffice it to say, your assistance allowed me to acquire much more insight into JS and effectively apply your logic to my use cases. I'm a Systems integrator by trade with virtually no programming experience, so this has been an eye opener to say the least..

All the accolades aside, I am very grateful once again for your help. Can't thank you enough!

Ron

 

0 Kudos
eoinbyrne
Expert
Expert
Jump to solution

Hi

Sorry, I've not had the time to log in for ages 🙂

No problem at all, just glad I could help