Page 1 of 1

JSON Output Formatting?

PostPosted: Wed Feb 22, 2017 12:34 am
by bcusick
Hey Guys,

I'm working with the RESTful plugin - and I was wondering how to properly (consistently) format the JSON output?

For example I have some object in code:

Code: Select all
var oProblem = {
   "id" : "",
   "problem" :  "",
   "date_added" : "",
   "date_resolved" : ""
}


Then I fill it up:

Code: Select all
oProblem.id = xxxx;
oProblem.problem = "Problem";
.... etc ...


The issue is - when the JSON comes out - it's in a different order:

Code: Select all
{
  "date_resolved" : "",
   "id" : xxxx,
   "problem" :  "Problem",
   "date_added" : ""
}


Is there a way I can keep it in the order I've specified (so it will match my API schema)?

Thanks in advance!

Bob

Re: JSON Output Formatting?

PostPosted: Wed Feb 22, 2017 3:59 am
by david
You access objects by key and arrays by index. Hence order of keys in object is not necessary (and not guaranteed in javascript). Said another way, the value of "oProblem.id" is always returned no matter the order "id" shows up as. Conversely, "oProblem[0]" is never used to get the value of the first key in an object.

Example of iterating objects in Servoy:

Code: Select all
/**
* @properties={typeid:35,uuid:"BD1E4BB4-F1B1-48C5-81BB-1571CD142A5B",variableType:-4}
*/
var myObjectSimple = function() {
   return {
      a: 1,
      b: 2,
      c: "3"
   }
}

/**
* @properties={typeid:35,uuid:"F1E8AC6B-6884-44C3-9C58-6A4B1ED7CB54",variableType:-4}
*/
var myObjectClosure = function () {
   // total up all numbers with startValue
   var aggregate = function (inputArray, startValue) {
      
      // inputArray is Array?
      if (Array.isArray(inputArray)) {
         inputArray.filter(function(item) {
            return typeof item === "number"
         })
         .map(function (item) {
            startValue += item
         })
      }
      return startValue
   }
   return {
      a: 1,
      b: 2,
      c: "3",
      calc: aggregate
   }
}

/**
* USAGE:    #1 processObject(myObjectSimple)  // output order not guaranteed
*             -> a: 1.0
*             -> b: 2.0
*             -> c: 3 
*          #2 processObject(myObjectClosure) // w/method on the object
*             -> a: 1.0
*             -> b: 2.0
*             -> c: 3
*             -> calc: 3.0 // result of object "api" method
*
* @properties={typeid:35,uuid:"C142B794-16A4-4D8E-9DC5-A64F6C690B3A",variableType:-4}
*/
var processObject = function (factoryFN) {
   var newObject = factoryFN()
   
   // Iterate object version #1
//   if (typeof newObject[prop] === "function") {
//      var sum = newObject[prop]([newObject.a, newObject.b, newObject.c], 0) // example of calling newObject.calc(...) at the destination
//      application.output(prop + ": " + sum)
//   }
//   else {
//      application.output(prop + ": " + newObject[prop])
//   }

   // Iterate object version #2 (preferred)
   Object.keys(newObject).forEach(function (prop) {
   if (typeof newObject[prop] === "function") {
      var sum = newObject[prop]([newObject.a, newObject.b, newObject.c], 0) // example of calling newObject.calc(...) at the destination
      application.output(prop + ": " + sum)
   }
   else {
      application.output(prop + ": " + newObject[prop])
   }
})


Iterating objects in the browser (after calling your REST api endpoint for example) is similar (replace "application.output(...)" with "console.log(...)")

Re: JSON Output Formatting?

PostPosted: Wed Feb 22, 2017 7:26 am
by ROCLASI
Hi Bob,

bcusick wrote:Is there a way I can keep it in the order I've specified (so it will match my API schema)?


Is there a specific reason to keep it in order?
As David already mentioned the order has no effect on accessing the data since you need to access it directly by property name.
If it's for display/document purposes you could keep an array with the property names in the correct order and iterate over that to fetch the values in order.
And as David already showed (although kinda buried in the code) you can get an Array with the property names of an object using the Object.keys(myObject) function.

Hope this helps.

Re: JSON Output Formatting?

PostPosted: Wed Feb 22, 2017 3:46 pm
by bcusick
Thanks guys! I know that the order doesn't matter - I was just wondering if there was a way to "prettify" the output. I know that there is no guaranteed "order" when working with object properties... but I just wanted to make sure I wasn't missing something really obvious. :D

David - I appreciate your in-depth explanation!

Robert - that's the route that I was going to go down if all else failed.

Again, many thanks to both of you!

Bob

Re: JSON Output Formatting?

PostPosted: Wed Feb 22, 2017 5:42 pm
by david
bcusick wrote:Thanks guys! I know that the order doesn't matter - I was just wondering if there was a way to "prettify" the output. I know that there is no guaranteed "order" when working with object properties... but I just wanted to make sure I wasn't missing something really obvious. :D


Yea, nothing at the end of that hole. But on a closely related note, changing up your object structure slightly to include an array of keys is a useful pattern. You can still directly access a specific object value by key (one step further removed, ie myObj.items.key instead of myObj.key) and you iterate the additional array of keys to process the keys in order:

Code: Select all
/**
* @properties={typeid:35,uuid:"33E547AA-6395-4EF9-8562-F1A6E6BB5301",variableType:-4}
*/
var myObjectOrdered = function() {
   return {items: {
            a: 1,
            b: 2,
            c: "3" },
         itemsOrder: ['a', 'b', 'c']
   }
}

/**
*
* USAGE:    processObjectOrdered(myObjectOrdered)  // output order guaranteed
*             -> [ 1.0, 2.0, 3 ]
*
* @properties={typeid:35,uuid:"9C49ECBB-A2AA-461A-AB39-33FD0530DBE5",variableType:-4}
*/
var processObjectOrdered = function(factoryFN) {
   var newObject = factoryFN()
   var sampleOutput = []
   
   // Iterate array and use to access object keys
   if ( newObject.hasOwnProperty('itemsOrder') && Array.isArray(newObject['itemsOrder']) ) {
      newObject['itemsOrder'].forEach(function(value) {
         sampleOutput.push(newObject['items'][value])
      })
   }
   
   application.output(sampleOutput)
}


For example if you're passing back functions instead of scalar values you could execute those functions in order and just choose a specific function to execute.

Re: JSON Output Formatting?

PostPosted: Fri Feb 24, 2017 7:10 pm
by bcusick
David - VERY interesting!

Thanks very much for the tip!

Re: JSON Output Formatting?

PostPosted: Thu Mar 02, 2017 7:06 am
by sbutler
a bit late on this, but with JSON, order isn't important (general) as others have mentioned. If you need to return things in a certain order, then you'll need to use an array in the JSON. Then the order is kept.

Normal Unordered JSON:
Code: Select all
var oProblem = {
   "id" : "",
   "problem" :  "",
   "date_added" : "",
   "date_resolved" : ""
}


Array Ordered JSON:
Code: Select all
var oProblem = [
   {"id" : ""},
   {"problem" :  ""},
   {"date_added" : ""},
   {"date_resolved" : ""}
]


So the ordered one is an array of objects/fields. Downside is it adds an extra level of nesting.

Re: JSON Output Formatting?

PostPosted: Fri Mar 03, 2017 4:31 pm
by bcusick
Scott - WHOA! That's really awesome! THANK YOU for that tip!

I was really just trying to see if I was missing something - but as long as I write docs that are clear - and document all the properties, datatypes, etc - it should be usable.

As this is my first stab at an API - I just didn't want to "Bob-ify" it and screw the pooch. :lol: