JSON module

The JSON module contains functions for reading and writing JSON data.

JSON is a text-based data exchange format based on the syntax for constructing Javascript objects. In the context of a scripting language like FlowScript, JSON is a method for transforming data (like records, sequences, numbers, texts) into text format and back.

First, note that all JSON documents also valid FlowScript syntax. You can copy any piece JSON into a FlowScript program, and it is immediately a valid record, array or other value.

Here, for example, we are declaring a variable test and assigning it to a value copied from the first example from the W3Schools JSON introduction :

let test = {"name": "John", "age": 30, "car": null};

The variable test is now declared as a record with fields name, age and car.

While all JSON data is valid FlowScript syntax, the reverse does not hold. Some types of values in FlowScript (such as functions) cannot be transformed into JSON.

Serializing JSON

In order to turn a FlowScript value into JSON data – that is, a text variable containing the JSON representation of the value – we can use the serialize function in the JSON module.

Using the same example object as above, we can use the serialize function to transform it into text.

let test = {"name": "John", "age": 30, "car": null};

let jsonData = JSON.serialize(test); // jsonData has type text

return jsonData.

Trying to serialize a value of a function type will result in a runtime error:

let addOne = function (x: number) => x + 1;
let recordContaningFunction = {f: addOne};

return JSON.serialize(recordContaningFunction); // ERROR: Function values cannot be converted to JSON.

Serializing binary data will convert the data to Base 64 text format.

Datetime values will be serialized as text in ISO 8601 format, including time zone offset:

return JSON.serialize({timestamp: now()}); 

Deserializing JSON

In order to turn JSON data (as a text value) into FlowScript objects, you use the deserialize function in the JSON module. In order to deserialize, we need to supply an expected type of the data. We supply that type as a type argument to the function.

Staying with the example mentioned above, here is how you might deserialize the data from a text variable.

// Define the expected format of the data.
type User = {name: text, age: number, car: text?};

// Data as JSON text
let data = '{"name": "John", "age": 30, "car": null}';

// Deserialize
let user = JSON.deserialize<User>(data);

return user.name; // returns text value "John".

If some member is declared in the type but missing in the JSON, it will be initialized with the member's default value (if set), or the default value for the member's type (if no default value set).

type User = {name: text, age: number = -1, car: text?};

let data = '{"name": "John"}'; // car and age are missing
let user = JSON.deserialize<User>(data);

// user.age will be -1 (the field's default value), and user.car will be null.

Sometimes it is necessary to distinguish members that are actually missing from the JSON. For such cases, we can deserialize as a smaller type containing only the members expected to be always present, and then use type narrowing to check for the presence of additional fields:

type User = {name: text};

let data = '{"name": "John", "age": 30}'; // user has "age", which is not in the type
let user = JSON.deserialize<User>(data);

if user is {age: number} {
    // user.age is available with value 30 in this branch.
    return user.age;
}
return 0;

Last updated