JSON vs XML: when did these data formats originate, and how are they used in RPG (and development in general)? Both have a tremendous history behind them and are either derived from, inspired by, or parent to a variety of other means to hold data. This article will draw a few mentions to content discussed in our previous blog posts on REST vs SOAP APIs (and a comparison). It is the second in a series of three articles focused on JSON (as well as its origins, general structure, and typical uses in RPG). The first article explores XML in a similar fashion, while the third draws comparisons between the two. Before getting too deep into the weeds, let’s define a few important terms mentioned in this series.
The realm of client-server communication is loaded with acronyms and terms to keep track of. To begin with, let’s elaborate upon several key terms, and what they mean.
Let’s dig into JSON and find out what each of its terms mean. As mentioned in the “Definitions” section, JSON stands for JavaScript Object Notation.
One of the most widely used programming languages, JavaScript can be found almost everywhere – almost every website you go to uses JavaScript. Its flexibility allows it to perform a variety of tasks such as calculate, manipulate, and validate data. In the context of JSON, both it and JavaScript have similar data types:
JavaScript | JSON | |
---|---|---|
1 | Numbers | Numbers |
2 | Strings | Strings |
3 | Objects (Object.Property) | Objects (JSON Object) |
4 | Arrays | Arrays |
5 | Functions | No Functions |
6 | Date (as Object) | No Date Support |
7 | Boolean (as Object) | Boolean |
8 | Null (as Object) | Null |
9 | Undefined | No Undefined |
In programming, an object is a conceptual entity used to represent something. For example, a Person could be an object. That Person object could contain properties such as name, age, occupation, or anything else that could be used to describe the person.
JSON would represent this as a string of information. Using a Person object as an example, some JSON representing a Person object could be as simple as a structure like…
{"name":"John"}
Notation can be described as the way a piece of syntax is represented in a program or language. JSON’s notation uses standards such as curly braces, square brackets, and commas.
Mozilla’s documentation site sums up JSON well,
JSON exists as a string — useful when you want to transmit data across a network. It needs to be converted to a native JavaScript object when you want to access the data. This is not a big issue — JavaScript provides a global JSON object that has methods available for converting between the two.
To get a broader understanding of JSON, as well as some trivia, let’s look into JSON’s initial history.
JSON, like XML, is built using a hierarchical tree structure beginning with a single root object (or array) and expanding into a variety of values, objects, and arrays. A JSON document might be structured like this:
// This is the opening curly brace of a JSON object
{
// This is a string data type
"name" : "John",
// This is a number data type
"age" : 45,
// This is a boolean data type
"active" : true,
// This is a null data type
"referredBy" : null,
// This is an array data type
"previousRoles" : ["Dish Washer", "Help Desk Technician", "RPG Programmer"],
// This is an object data type
"user" : {"member" : true, visitCount : 42, userName : "shinyCrown467"},
// This will return as a string; JSON does not have a native date data type
"dob" : "1/1/1977"
// This is the closing curly brace of a JSON object
}
RPG API Express helps you quickly develop JSON with a kit of subprocedure APIs. Some of the following structural rules of JSON data types will be shown along with an RXS subprocedure that creates an equivalent chunk of JSON code.
When building JSON with RPG API Express, your programs will require two data structures: one to initialize the JSON document’s construction and another to create the root curly braces of the document. Other data structures may be required for objects and arrays; we’ll explore that further down. For now, these are the data structures required to initialize JSON composition:
Dcl-Ds CreateJsonDS LikeDS(RXS_CreateJsonDS_t);
Dcl-Ds RootDS LikeDS(RXS_JsonStructureDS_t);
While JSON has many similarities to JavaScript’s object notation, JSON has some syntactical differences that should be noted.
JSON documents begin with a base structure used to contain the document’s contents. Base structures can take form as either objects (using curly braces) or arrays (using square brackets). Well-formed JSON documents require a root (or opening) and terminating (or closing) brace / bracket. It’s important to note that while roots are used for creating a structure, they are not used in key / value pairs. Unlike root objects / arrays, child objects / arrays within a parent need a key. In this example…
// Base structure
{
// Example contents (string)
"string": "text",
// Example contents (object)
"info": { },
// Example contents (array)
"list": [ ]
}
… notice how the base structure doesn’t need a key before its declaration. Any JSON field or object/array can be added immediately. A child object however does require a key; in this case, “info”. Likewise, a child array also requires a key, such as “list” in the example.
RPG API Express accomplishes something similar through two subprocedures which build and initialize the structure of a JSON document; namely, with opening and closing curly braces / square brackets. This would be accomplished by specifying:
CreateJsonDS.JsonStructureType = RXS_JSON_STRUCTURE_OBJECT;
// or
CreateJsonDS.JsonStructureType = RXS_JSON_STRUCTURE_ARRAY;
Then, that data structure would be passed into the RXS_CreateJson() subprocedure, and the result would be assigned to RootDS. The value of RootDS is now either { } or [ ].
RootDS = RXS_CreateJson( CreateJsonDS );
JSON objects always begin with an opening curly brace, and terminate with a closing curly brace. An example JSON object might look like this:
{
"name":"Jane",
"age":29
}
RPG API Express makes creating JSON objects a breeze. Assuming you’ve already created a base structure or RootDS like the example above, adding another object requires only the RXS_ComposeJsonObject() subprocedure assigned to a data structure (ChildDS), with the first parameter specifying a key and the second parameter specifying which data structure the object should be added to (in this case, its parent RootDS).
Dcl-Ds ChildDS LikeDS(RXS_JsonStructureDS_t);
// …
ChildDS = RXS_ComposeJsonObject( 'child' : RootDS);
The composed JSON would look like this:
{
"child":{}
}
Like objects, arrays are often used as the root of a document. Arrays are used to contain data and can represent a set of fields, objects, and / or arrays- even a combination of multiple data types. For example, these would all count as valid JSON arrays:
[1,2,3]
[true,false,true]
[{"CEOs":
[{"nameA":"Arvind","nameB":"Ginny","nameC":"Samuel"},
{"name1":"Gates","name2":"Ballmer","name3":"Nadella"}]
}]
["abc",17,{"firstName","lastName",12345},null]
Creating an array in RXS involves creating a data structure to hold its contents and assigning an array of elements to it via the RXS_ComposeJsonArray() subprocedure. For this example, assume you’ve initialized and built a JSON root:
Dcl-Ds VehicleListDS LikeDS(RXS_JsonStructureDS_t);
// …
VehicleListDS = RXS_ComposeJsonArray( 'vehicle' : RootDS );
RXS_ComposeJsonString( *Omit : 'Neon' : VehicleListDS );
RXS_ComposeJsonString( *Omit : 'Windstar' : VehicleListDS );
RXS_ComposeJsonString( *Omit : 'Rio' : VehicleListDS );
If the composed VehicleListDS array was placed into an object-formed RootDS, the resulting JSON would look like this:
{
"vehicle": ["Neon","Windstar","Rio"]
}
Numbers in JSON are straightforward. Numeric data types are always on the value side of the key/value pair and can be represented as positive or negative numbers. Integers, decimal point values, and exponent notation are all accepted. It is important to note that the JSON spec does not specify to what precision it counts decimals, and more specifically decimals within JSON are treated as floating point values. This means that the system processing the JSON will determine how precise a given number is, and there is a risk of some loss of precision. Some examples of valid numerical values include:
1337
-8601
12.3
4.5678e9
Creating numbers with RXS is easy. The process involves specifying three parameters to pass into the RXS_ComposeJsonNumber() subprocedure: the key, value, and parent data structure (containing a parent JSON object or array). In order to retain data precision, when composing JSON with RXS, numbers need to be passed as strings, or with the %Char built-in function:
/*
RXS_ComposeJsonNumber( 'id' : '7' : RootDS );
itemPrice = 12.50;
RXS_ComposeJsonNumber( 'price' : %Char(itemPrice) : RootDS );
*/
Strings represent character data in JSON. They follow a very simple rule: string values must be surrounded by quotation marks. In RPG, string data containing numbers can be converted using the %Int or %Dec built-in functions. Here’s a few examples of valid string data:
"JSON in RPG"
"1701"
"2022-31-12T13:45:00.000Z"
Note, as stated by JSONata, “JSON does not have a built-in type for date/time values. The general consensus is to store the date/time value as a string in ISO 8601 format.”
String data is constructed similarly to numeric data; 3 parameters are passed into a subprocedure; in this case RXS_ComposeJsonString().
RXS_ComposeJsonString( 'hello' : 'world' : RootDS );
Programs use booleans to represent true or false values. In JSON, only…
true
… and…
false
… are syntactically legal. Terms that conceptually represent booleans such as Yes/No, 1/0, or On/Off are not allowed.
Booleans are easy to create in RXS. To specify and add one to JSON objects or arrays requires the RXS_ComposeJsonBoolean() subprocedure. Here’s an example of adding JSON booleans to a JSON object:
RXS_ComposeJsonBoolean( 'value' : RXS_JSON_TRUE : RootDS );
RXS_ComposeJsonBoolean( 'enabled' : RXS_JSON_FALSE : RootDS );
Null values represent something that is empty or does not exist. In JSON, null is always specified as null…
null
Null is the most straightforward data type to create in RXS. Using the RXS_ComposeJsonNull() subprocedure requires only two parameters: one for the key, and the other for the data structure holding a JSON object or array.
RXS_ComposeJsonNull( 'value' : RootDS );
JSON is the most widely used data format available, and one can find companies everywhere using it. In fact, as stated by Seva Safris in his excellent deep look into JSON vs XML, JSON overtook XML in usage within the past five years. JSON’s lightweight format makes it ideal when working with APIs. For example, the Big Five (Google, Amazon, Meta, Apple, and Microsoft) all use JSON APIs in some way, such as through YouTube, AWS, Messenger, App Store, and Azure.
Many of our customers and business partners continue to use JSON to provide endpoints for consuming their business data. Across the web, JSON continues to be a tool for learning and growth. For example, programmableweb.com – a site commonly used to find web services for testing purposes – provides a large catalog of public APIs and documentation pages. Looking up “XML API” in their search function yields 121 pages of results. Looking up “JSON API” yields over twice as many results at 250 pages.
Compared to XML, JSON is a more flexible, condensed format. JSON comes with a variety of benefits:
When building JSON documents or when sending JSON data over HTTP, having a suite of tools helps drastically reduce your development time. Our development team uses a variety of tools to accomplish programming goals, whether connecting to a new API, assisting new customers with a proof of concept, or prototyping a new web service. We recommend resources like these in order to help your own development:
JSON is typically used in various parts of your RPG programs. As mentioned above, JSON is frequently used when APIs interchange data. When sending JSON to a web API, your program will need to construct the JSON. A variety of options are available, such as through native tools on your IBM i or via open source development tools. You can create JSON with RPG API Express using the JSON composition subprocedures. A full tutorial on JSON development with RXS can be found here.
After constructing JSON, your program will often send it to an API through a transmitted GET or POST request via HTTP. Upon receiving your JSON-formatted request, the server your program is connecting with will send back a response (typically also containing JSON). Your RPG programs can transmit JSON most easily by using the RXS_Transmit() subprocedure which requires only a few lines of RPG code for full configuration with an API.
After receiving the response JSON, your program will usually parse the information. In relation to an API workflow, parsing is a process that involves extracting the contents of a semi-structured file (i.e. XML & JSON) for further processing. When parsing JSON in RPG, programs will typically store the parsed data into DB2 variables declared within the program itself. Other uses include parsing directly into program variables or sending JSON into a file within the IFS (for instance, by using the RXS_PutStmf() subprocedure). You can learn more about parsing JSON with RPG API Express here.
JSON-centric APIs are in no short supply; after all, JSON is a lightweight, easy-to-read data format that couples well with existing languages. Many RPG developers want to build JSON though not necessarily at production-scale. Hobbyist and small-scale applications can still benefit from open source tools on the IBM i.
When going for a hybridized “RPG + open source” route, such programs might use a few different tools to accomplish their respective Compose, Parse, and Transmit steps. For example, to compose JSON in RPG, one might use DATA-GEN which uses enormous data structures to contain JSON objects. To transmit data across HTTP, HTTPAPI is a popular tool by Scott Klement. Finally, to parse data, open source developers can make use of YAJL which is a library of JSON-type tools that are invoked during program calls and works with third-party external parsers like YAJLINTO. These can be coupled with DATA-INTO which likewise uses a series of large data structures.
While open source is helpful (especially for learning new skills in non-production shops), it comes at the expense of not having a dedicated support team who can answer questions related to JSON in RPG and API communication in general.