RPG API Express opens your IBM i to web services everywhere, but to create JSON in RPG, you’ll first need to know how. After Kato Integration’s release of RPG API Express version 3.4.0, we have added numerous features and bugfixes, enhancing RPG API Express’s parsing and composition APIs. Because of these changes, we’re updating some of our most perennial content. We have also updated this blog post’s example code to the more modern Free-Format RPGLE.
With the release of RPG API Express version 3.4, Kato Integrations 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.
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: Now in RPG API Express 3.4 – Enhanced 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. We will refer to this code throughout the post.
Ctl-Opt DftActGrp(*No) ActGrp(*Caller) BndDir('RXSBND');
/COPY QRPGLECPY,RXSCB
// Create JSON DataStructure
Dcl-Ds CreateJsonDS LikeDS(RXS_CreateJsonDS_t);
// Root JSON Object Data Structure
Dcl-Ds RootObjDS LikeDS(RXS_JsonStructureDS_t);
// Address JSON Object
Dcl-Ds AddressObjDS LikeDS(RXS_JsonStructureDS_t);
// Phone Number JSON Array
Dcl-Ds PhoneArrDS LikeDS(RXS_JsonStructureDS_t);
// Final JSON String
Dcl-S JsonString Like(RXS_Var64Kv_t);
// Configures the output STMF
Dcl-Ds StmfDS LikeDS(RXS_PutStmfDS_t);
// 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;
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 us here for a free 30-day trial, and to discuss how RPG API Express can meet your JSON communication requirements!
Existing RPG API Express customers with a paid maintenance contract are eligible to the latest version of RPG API Express for no additional cost – contact our support team here for more information!