Skip to main content

JSON for canvas apps

Canvas apps largely handle the details of communicating with other systems through connectors.  Normally you don’t need to worry about how data is packaged and sent over the wire.

Some systems and APIs are specifically designed to work with JavaScript Object Notation (JSON).  A notation which looks very similar to canvas record and table notation, but it isn’t exactly the same.  Parsing and generating JSON in a canvas app is possible today but it is very time consuming and tedious.

Help has arrived for generating JSON: the aptly named JSON function.   It will return the JSON string for an arbitrary canvas data structure.  Of particular note, it supports images and media enabling you to base64 encode an image taken with the camera.

All the details can be found in the JSON documentation.  This function is live in a few regions now and will be rolling out to all regions shortly.

Examples

Imagine executing this formula:

ClearCollect( CityPopulations, 
    { City: "London", Country: "United Kingdom", Population: 8615000 }, 
    { City: "Berlin", Country: "Germany", Population: 3562000 }, 
    { City: "Madrid", Country: "Spain", Population: 3165000 }, 
    { City: "Hamburg", Country: "Germany", Population: 1760000 }, 
    { City: "Barcelona", Country: "Spain", Population: 1602000 }, 
    { City: "Munich", Country: "Germany", Population: 1494000 } 
); 
ClearCollect( CitiesByCountry, GroupBy( CityPopulations, "Country", "Cities" ) )

Which results in this data structure in CitiesByCountry:

If we’d like a compact JSON representation, suitable for sending over a network:

JSON( CitiesByCountry )

Which returns:

[{"Cities":[{"City":"London","Population":8615000}],"Country":"United Kingdom"},{"Cities":[{"City":"Berlin","Population":3562000},{"City":"Hamburg","Population":1760000},{"City":"Munich","Population":1494000}],"Country":"Germany"},{"Cities":[{"City":"Madrid","Population":3165000},{"City":"Barcelona","Population":1602000}],"Country":"Spain"}]

And if we would like a more readable version for humans:

JSON( CitiesByCountry, JSONFormat.IndentFour )

Which returns:

[
    {
        "Cities": [
            {
                "City": "London",
                "Population": 8615000
            }
        ],
        "Country": "United Kingdom"
    },
    {  
        "Cities": [
            {
                "City": "Berlin",
                "Population": 3562000
            },
            {
                "City": "Hamburg",
                "Population": 1760000
            },
            {
                "City": "Munich",
                "Population": 1494000
            }
        ],
        "Country": "Germany"
    },
    {
        "Cities": [
            {
                "City": "Madrid",
                "Population": 3165000
            },
            {
                "City": "Barcelona",
                "Population": 1602000
            }
        ],
        "Country": "Spain"
    }
]

To serialize an image, this example being the sample image included with the Image control:

JSON( SampleImage, JSONFormat.IncludeBinaryData )

Results in:

"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxzdmcgdmVyc2lvbj0iMS4xIg0KCSB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczphPSJodHRwOi8vbnMuYWRvYmUuY29tL0Fkb2JlU1ZHVmlld2VyRXh0ZW5zaW9ucy8zLjAvIg0KCSB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjI3MHB4IiBoZWlnaHQ9IjI3MHB4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyNzAgMjcwIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCgk8ZyBjbGFzcz0ic3QwIj4NCgkJPHJlY3QgeT0iMC43IiBmaWxsPSIjRTlFOUU5IiB3aWR0aD0iMjY5IiBoZWlnaHQ9IjI2OS4zIi8+DQoJCTxwb2x5Z29uIGZpbGw9IiNDQkNCQ0EiIHBvaW50cz0iMjc3LjksMTg3LjEgMjQ1LDE0My40IDE4OC42LDIwMi44IDc1LDgwLjUgLTQuMSwxNjUuMyAtNC4xLDI3MiAyNzcuOSwyNzIiLz4NCgkJPGVsbGlwc2UgZmlsbD0iI0NCQ0JDQSIgY3g9IjIwMi40IiBjeT0iODQuMSIgcng9IjI0LjQiIHJ5PSIyNC4zIi8+DQoJPC9nPg0KPC9zdmc+"

And when that is shown in a browser, as in this blog post:

Important notes

  1. Unsupported data types, such as control and record references, will result in an error.  There is an IgnoreUnsupportedTypes flag you can pass to suppress this error.  We defaulted to the error so that someone would not be surprised when a field did not appear in the result.
  2. By default we do not include image and media data types, they too will result in an error.  You can pass a flag to IncludeBinaryData or IgnoreBinaryData depending on your needs.  We are concerned about the size of the result and the impact on performance.  There is no size limit for binary data or text strings beyond available memory on the device.
  3. Because JSON can be memory and compute intensive, we don’t allow it to participate in normal data flow.  You can only invoke JSON from a behavior formula, such as the OnSelect of a button.  More than likely you will be using this function to make an imperative call to a service anyway and that will already be in a behavior formula.  You can always put the result in a variable to be used in data flow.

More small features

Along the way, we also added two small features:

The ColorValue function has been enhanced to accept the eight digit #rrggbbaa notation which includes an alpha channel, the same notation emitted by JSON for a color value.  Previously we only supported six digit #rrggbb notation.

Transparent has been added to the Color enumeration.  No longer do you need to invoke a function to get a transparent color, such as RGBA(0,0,0,0), instead you can use the more obvious Color.Transparent.