This article was originally posted on our RPG-XML Suite product website, and has since been updated.
With the release of RPG-XML Suite version 3.3, Krengel Technology is bringing JSON to the IBM i. Take advantage of our extensive toolkit to easily build your web service communication solution, all in native RPG.
What is JSON?
Much like XML, JSON is a data interchange format – a way to pass a collection of data from one computer program to another. In our line of business, this most often means passing data through a web service.
JSON is becoming increasingly popular as a means of web service data communication and data transfer – most of Google’s APIs use JSON request and response data, and IBM’s Bluemix and Watson services all use JSON. For a more in-depth look at what JSON is and what you can do with it, read our introductory blog post here: https://www.krengeltech.com/2016/07/now-in-rpg-xml-suite-3-3-json-support/
In this post, the first in a series of JSON tutorials, we’ll show you how to use the RXS JSON APIs to easily compose a JSON document in native RPG in your IBM i.
Let’s say you are at a trade show, and you’re keeping track of people that stop by your booth. A JSON object for such a person might look something like this:
{ "name" : "Yvonne Osbourne", "salesProspect" : true, "address" : { "number" : 11405, "apartment" : null, "street" : "Maple Glades Lane", "city" : "Mankato", "state" : "MN", "postCode" : "56001" }, "phone" : [ "608-555-0014", "605-555-0188" ], "email" : "yvosbourne@email.com" }
We’ll build this sample record using the RXS JSON composition APIs. The full source code for this program can be found below, and you can click the right-hand option in the toolbar to open the code in a new window. We will refer to this code throughout the post.
H DFTACTGRP(*NO) ACTGRP(*CALLER) BNDDIR('RXSBND') /COPY QRPGLECPY,RXSCB D CreateJsonDS DS LikeDS(RXS_CreateJsonDS_t) * Root JSON Object Datastructure D RootObjDS DS LikeDS(RXS_JsonStructureDS_t) * Address JSON Object D AddressObjDS DS LikeDS(RXS_JsonStructureDS_t) * Phone Number JSON Array D PhoneArrDS DS LikeDS(RXS_JsonStructureDS_t) * Final JSON String D JsonString S Like(RXS_Var64Kv_t) * Configures the output STMF D StmfDS DS LikeDS(RXS_PutStmfDS_t) /FREE // reset JSON datastructures RXS_ResetDS( CreateJsonDS : RXS_DS_TYPE_CREATEJSON ); RXS_ResetDS( RootObjDS : RXS_DS_TYPE_JSONSTRUCTURE ); RXS_ResetDS( AddressObjDS : RXS_DS_TYPE_JSONSTRUCTURE ); RXS_ResetDS( PhoneArrDS : RXS_DS_TYPE_JSONSTRUCTURE ); RXS_ResetDS( StmfDS : RXS_DS_TYPE_PUTSTMF ); // initialize JSON object composition CreateJsonDS.JsonStructureType = RXS_JSON_STRUCTURE_OBJECT; RootObjDS = RXS_CreateJson( CreateJsonDS ); // compose JSON object components RXS_ComposeJsonString( 'name' : 'Yvonne Osbourne' : RootObjDS ); RXS_ComposeJsonBoolean( 'salesProspect' : RXS_JSON_TRUE : RootObjDS ); // compose address child object (child of root object) AddressObjDS = RXS_ComposeJsonObject( 'address' : RootObjDS ); // compose the child fields of the address object RXS_ComposeJsonNumber( 'number' : '11405' : AddressObjDS ); RXS_ComposeJsonNull( 'apartment' : AddressObjDS ); RXS_ComposeJsonString( 'street' : 'Maple Glades Lane' : AddressObjDS ); RXS_ComposeJsonString( 'city' : 'Mankato' : AddressObjDS ); RXS_ComposeJsonString( 'state' : 'MN' : AddressObjDS ); RXS_ComposeJsonString( 'postCode' : '56001' : AddressObjDS ); // compose the phone number array (child of root object) PhoneArrDS = RXS_ComposeJsonArray( 'phone' : RootObjDS ); // add elements to the array RXS_ComposeJsonString( *Omit : '608-555-0014' : PhoneArrDS ); RXS_ComposeJsonString( *Omit : '608-555-0188' : PhoneArrDS ); // compose a string element to the root object RXS_ComposeJsonString( 'email' : 'yvosbourne@email.com' : RootObjDS ); // retrieve the composed JSON string CreateJsonDS.Prettify = RXS_YES; JsonString = RXS_GetJsonString( CreateJsonDS ); // to preserve the whitespace, we'll write the composed JSON // string to an IFS file StmfDS.Stmf = '/tmp/composeJsonDemo.json'; RXS_PutStmf( JsonString : StmfDS ); // this cleans up the memory used by the JSON operations RXS_DestroyJson( CreateJsonDS ); *INLR = *On; return; /END-FREE
RXS composes JSON from the root down – we need to start with our base JSON object, which we’ll initialize using RXS_CreateJson():
CreateJsonDS.JsonStructureType = RXS_JSON_STRUCTURE_OBJECT; RootObjDS = RXS_CreateJson( CreateJsonDS );
CreateJsonDS is an RXS_CreateJsonDS_t data structure that is used to configure the JSON composition engine. The JsonStructureType field is used to specify whether the root element we are building is an object (as it is here) or an array. RootObjDS is an RXS_JsonStructureDS_t data structure, and it will be used to hold all of the child elements in our JSON object.
Next, we will add some individual elements to the JSON object. The RXS_ComposeJson* APIs (except for RXS_ComposeJsonNull) accept three parameters – the name and value of the element, and an RXS_JsonStructureDS_t data structure to which the element will be added. Here, we are adding the string element “name” to our RootObjDS structure using RXS_ComposeJsonString():
RXS_ComposeJsonString( 'name' : 'Yvonne Osbourne' : RootObjDS );
This subprocedure composes the line:
"name":"Yvonne Osbourne"
When using RXS_ComposeJsonBoolean() to compose a boolean element, we will assign the value in the second parameter using the RXS helper fields RXS_JSON_TRUE and RXS_JSON_FALSE. These fields are constants which represent the RPG boolean values of *On
for true
and *Off
for false
. Here is how we add the boolean element “salesProspect” to our JSON object:
RXS_ComposeJsonBoolean( 'salesProspect' : RXS_JSON_TRUE : RootObjDS );
This writes the line:
"salesProspect":true
It is important to note the difference between writing a boolean value using RXS_ComposeJsonBoolean(), as above, and using RXS_ComposeJsonString() to write the following:
"salesProspect":"true"
Unlike XML, in which all fields are treated as character data, JSON is strongly typed and supports several data types, including booleans. As such, a string value of “true” is treated differently than the boolean value true
, and we must be sure to use the correct composition subprocedure.
We are writing the street address as a child object, and we’ll use RXS_ComposeJsonObject() to add it to our root object:
AddressObjDS = RXS_ComposeJsonObject( 'address' : RootObjDS );
This subprocedure returns a new RXS_JsonStructureDS_t, and we’ll use this structure to write the address child elements just like how we are using RootObjDS to compose the other elements.
RXS_ComposeJsonNumber( 'number' : '11405' : AddressObjDS ); RXS_ComposeJsonNull( 'apartment' : AddressObjDS ); RXS_ComposeJsonString( 'street' : 'Maple Glades Lane' : AddressObjDS ); RXS_ComposeJsonString( 'city' : 'Mankato' : AddressObjDS ); RXS_ComposeJsonString( 'state' : 'MN' : AddressObjDS ); RXS_ComposeJsonString( 'postCode' : '56001' : AddressObjDS );
Note that we pass the element value into RXS_ComposeJsonNumber() as character data, rather than an integer or decimal. The subprocedure will write the value as a JSON numeric data type.
Also note that we are writing a null value to the “apartment” element, using RXS_ComposeJsonNull(). This API accepts only two parameters – the name of the field, and the RXS_JsonStructureDS_t data structure of the parent JSON element. As with boolean values, JSON recognizes a null data type, and it is important not to use RXS_ComposeJsonString() to write “null” instead.
We create and compose the phone number array in a similar manner as we did the address object, using RXS_ComposeJsonArray() to create the RXS_JsonStructureDS_t data structure for the array:
PhoneArrDS = RXS_ComposeJsonArray( 'phone' : RootObjDS ); RXS_ComposeJsonString( *Omit : '608-555-0014' : PhoneArrDS ); RXS_ComposeJsonString( *Omit : '608-555-0188' : PhoneArrDS );
For both of the phone numbers, the first parameter is passed as *Omit
when calling RXS_ComposeJsonString() because elements written to a JSON array, regardless of type, cannot be given names.
We’ll write one last string element to the root object:
RXS_ComposeJsonString( 'email' : 'yvosbourne@email.com' : RootObjDS );
Now that we’ve finished composing the elements in our JSON object, we need to retrieve the formatted JSON string. By default, the composition engine writes the JSON data with minimal whitespace, but we’re going to take advantage of the Prettify option in CreateJsonDS to make the output more readable, then retrieve the composed JSON string into a variable using RXS_GetJsonString():
CreateJsonDS.Prettify = RXS_YES; JsonString = RXS_GetJsonString( CreateJsonDS );
The JsonString field now contains our composed and formatted JSON object. To preserve the whitespace, we’ll write the composed JSON string to an IFS file using RXS_PutStmf():
StmfDS.Stmf = '/tmp/composeJsonDemo.json'; RXS_PutStmf( JsonString : StmfDS );
Here is the output file:
Now that our JSON data is composed, we’re ready to put it to use – whether that’s by passing it as a request to a web service, writing it to a file, sending a response from the web service you’re offering, or however else you need. JSON is an incredibly flexible, powerful format, and RXS is here to help you take full advantage.
In our next tutorial post, we’ll discuss how to read and use composed JSON data using the RXS JSON parsing API.
Does your business need to handle JSON data on your IBM i? Contact our sales team at sales@krengeltech.com to discuss how RPG-XML Suite can meet your JSON communication requirements!
Existing RXS customers with a paid maintenance contract are eligible to upgrade to RXS 3.3 for no additional cost – contact our support team at isupport@krengeltech.com for more information!
2 Responses