Example 4

This example program demonstrates the basic structure of an RPG program utilizing RXS to compose a JSON string with repeating elements.

**FREE
Ctl-Opt ActGrp(*Caller) BndDir('RXSBND') Option(*NoDebugIO) ExtBinInt(*Yes) DecEdit('0.')
  Text('Ex. 4 - JSON Compose');

/COPY QRPGLECPY,RXSCB

Dcl-Ds PutStmfDS LikeDS(RXS_PutStmfDS_t);

Dcl-Ds CreateJsonDS LikeDS(RXS_CreateJsonDS_t);
Dcl-Ds RootDS LikeDS(RXS_JsonStructureDS_t);
Dcl-Ds UsersArrayDS LikeDS(RXS_JsonStructureDS_t);
Dcl-Ds UserObjectDS LikeDS(RXS_JsonStructureDS_t);
Dcl-Ds JsonArrayDS LikeDS(RXS_JsonStructureDS_t);

Dcl-S i Uns(3);
Dcl-S JSON Like(RXS_Var64Kv_t);
Dcl-S dateVal Char(10);

monitor;
  // Use RXS_ResetDS to ensure that the CreateJsonDS data structures is
  //  properly initialized. We don't have to use this on the various
  //  RXS_JsonStructureDS_t structures because the other RXS subprocedures
  //  will handle those for us.
  RXS_ResetDS( CreateJsonDS : RXS_DS_TYPE_CREATEJSON );

  // Create root JSON Object
  CreateJsonDS.Prettify = RXS_JSON_TRUE;
  CreateJsonDS.JsonStructureType = RXS_JSON_STRUCTURE_OBJECT;
  RootDS = RXS_CreateJson( CreateJsonDS );

  // Create JSON Array named users & attach to RootDS
  UsersArrayDS = RXS_ComposeJsonArray( 'users' : RootDS );

  // Loop through and add multiple objects to a JSON Array named "users".
  //  Typically you'd want to use a normal RPG database read loop here
  //  instead of a 'for' loop.
  for i = 1 to 3;
    // Create object for a customer, attach to array
    UserObjectDS = RXS_ComposeJsonObject( *Omit : UsersArrayDS );

    // Add various character fields & data to the users object we just created.
    RXS_ComposeJsonString( 'firstName' : 'First Name' : UserObjectDS );
    RXS_ComposeJsonString( 'lastName' : 'Last Name' : UserObjectDS );
    RXS_ComposeJsonString( 'email' : 'Email Address' : UserObjectDS );
    RXS_ComposeJsonString( 'username' : 'Username' : UserObjectDS );
    RXS_ComposeJsonString( 'password' : 'Password' : UserObjectDS );
  endfor;

  // The next few parts of this JSON structure are a series of arrays.
  //  We could define D spec data structure for each if we wanted to,
  //  but it's not required. We still need to ensure we're attaching
  //  them to our root object RootDS though.

  JsonArrayDS = RXS_ComposeJsonArray( 'requiredCourseIds' : RootDS );

  // Again, you'd probably be reading one or more child records out of
  //  a physical file here with an RPG read loop instead of a 'for' loop.
  for i = 1 to 10;
    // Note that the key difference between a JSON Object and a
    //  JSON Array is that a JSON Object can contain one or more
    //  name/value pairs (and the values can be of any type - a child
    //  JSON Object, a JSON Array, or just a plain string/int/etc value)

    // A JSON Array can hold one or more values ONLY. The values a JSON
    //  Array holds must all be of the same type (e.g. all JSON Object,
    //  all plain string/int/etc values, or even another JSON Array),
    //  and cannot have a name associated with them.

    // The easiest way to think about these two is that a JSON Object
    //  is like an RPG data structure, whereas a JSON Array is like
    //  an RPG data structure or normal field but with the Dim keyword
    //  used.

    // Because we can't name the values we're putting in our array, the
    //  second parm for RXS_ComposeJsonNumber() must be *OMIT.

    // We're using RXS_ComposeJsonNumber() to ensure that in the JSON
    //  the values we're passing show up as numeric (e.g. not wrapped
    //  in double quotes)

    // To handle large numbers effectively, RXS_ComposeJsonNumber()
    //  actually accepts a character representation of a number as
    //  opposed to an RPG numeric field type.
    RXS_ComposeJsonNumber( *Omit : %Char(i) : JsonArrayDS );
  endfor;

  // We're re-using the JsonArrayDS structure for the next few arrays
  //  as they are very simple arrays but the whole process is otherwise
  //  the same as for requiredCourseIds[]
  JsonArrayDS = RXS_ComposeJsonArray( 'courseIds' : RootDS );
  for i = 1 to 10;
    RXS_ComposeJsonNumber( *Omit : %Char(i * 2) : JsonArrayDS );
  endfor;

  JsonArrayDS = RXS_ComposeJsonArray( 'seriesIds' : RootDS );
  for i = 1 to 10;
    RXS_ComposeJsonNumber( *Omit : %Char(i * 3) : JsonArrayDS );
  endfor;

  JsonArrayDS = RXS_ComposeJsonArray( 'groupIds' : RootDS );
  for i = 1 to 10;
    RXS_ComposeJsonNumber( *Omit : %Char(i * 4) : JsonArrayDS );
  endfor;

  // Next, we need to add a date named datestamp to our RootDS.
  //  JSON doesn't have a 'date' data type, so we add this as a
  //  string and do whatever formatting the API we're calling requires.
  // In this case we're using *ISO YYYY-MM-DD date format
  dateVal = %Char( %Date() : *ISO );
  RXS_ComposeJsonString( 'datestamp' : dateVal : RootDS );

  // Next we're going to add JSON boolean and null values
  RXS_ComposeJsonBoolean( 'processed' : RXS_JSON_TRUE : RootDS );
  RXS_ComposeJsonNull( 'referenceId' : RootDS );

  // Now that we've added all of the data fields to our JSON object,
  //  let's generate our JSON string
  JSON = RXS_GetJsonString( CreateJsonDS );

  // Dump JSON to file
  RXS_ResetDS( PutStmfDS : RXS_DS_TYPE_PUTSTMF );
  PutStmfDS.Stmf = '/tmp/json_excompose1.txt';
  RXS_PutStmf( JSON : PutStmfDS );

on-error;
  RXS_DestroyJson( CreateJsonDS );
endmon;

// Always call RXS_DestroyJson() to free up the memory we used.
// This must be called AFTER we retrieve our string
//  with RXS_GetJsonString(), or there will be nothing to retrieve!
// It is enough to just call RXS_DestroyJson() on the CreateJsonDS data
//  structure - it will free the memory used by all of the child
//  data structures that were linked to it as well.
RXS_DestroyJson( CreateJsonDS );

*INLR = *ON;
return;
 
     H DFTACTGRP(*NO) ACTGRP(*CALLER) BNDDIR('RXSBND') OPTION(*NODEBUGIO)
     H EXTBININT(*YES) DECEDIT('0.')
     H TEXT('Fixed Format Ex. 4 - JSON Compose')

      /COPY QRPGLECPY,RXSCB

     D PutStmfDS       DS                  LikeDS(RXS_PutStmfDS_t)
     D CreateJsonDS    DS                  LikeDS(RXS_CreateJsonDS_t)
     D RootDS          DS                  LikeDS(RXS_JsonStructureDS_t)
     D UsersArrayDS    DS                  LikeDS(RXS_JsonStructureDS_t)
     D UserObjectDS    DS                  LikeDS(RXS_JsonStructureDS_t)
     D JsonArrayDS     DS                  LikeDS(RXS_JsonStructureDS_t)

     D i               S              3U 0
     D JSON            S                   Like(RXS_Var64Kv_t)
     D dateVal         S             10A
      /FREE
       monitor;

         // Use RXS_ResetDS to ensure that the CreateJsonDS data structures is
         //  properly initialized. We don't have to use this on the various
         //  RXS_JsonStructureDS_t structures because the other RXS
         //  subprocedures will handle those for us.
         RXS_ResetDS( CreateJsonDS : RXS_DS_TYPE_CREATEJSON );

         // Create root JSON Object
         CreateJsonDS.Prettify = RXS_JSON_TRUE;
         CreateJsonDS.JsonStructureType = RXS_JSON_STRUCTURE_OBJECT;
         RootDS = RXS_CreateJson( CreateJsonDS );

         // Create JSON Array named users & attach to RootDS
         UsersArrayDS = RXS_ComposeJsonArray( 'users' : RootDS );

         // Loop through and add multiple objects to the JSON Array named
         //  "users". Typically you'd want to use a normal RPG database
         //  read loop here instead of a 'for' loop.
         for i = 1 to 3;

           // Create object for a customer, attach to array
           UserObjectDS = RXS_ComposeJsonObject( *Omit : UsersArrayDS );

           // Add various character fields & data to the users object we just
           //  created.
           RXS_ComposeJsonString( 'firstName' : 'First Name' : UserObjectDS );
           RXS_ComposeJsonString( 'lastName' : 'Last Name' : UserObjectDS );
           RXS_ComposeJsonString( 'email' : 'Email Address' : UserObjectDS );
           RXS_ComposeJsonString( 'username' : 'Username' : UserObjectDS );
           RXS_ComposeJsonString( 'password' : 'Password' : UserObjectDS );
         endfor;

         // The next few parts of this JSON structure are a series of arrays.
         //  We could define D spec data structure for each if we wanted to,
         //  but it's not required. We still need to ensure we're attaching
         //  them to our root object RootDS though.

         JsonArrayDS = RXS_ComposeJsonArray( 'requiredCourseIds' : RootDS );

         // Again, you'd probably be reading one or more child records out of
         //  a physical file here with an RPG read loop instead of a
         //  'for' loop.
         for i = 1 to 10;
           // Note that the key difference between a JSON Object and a
           //  JSON Array is that a JSON Object can contain one or more
           //  name/value pairs (and the values can be of any type - a child
           //  JSON Object, a JSON Array, or just a plain string/int/etc value)

           // A JSON Array can hold one or more values ONLY. The values a JSON
           //  Array holds must all be of the same type (e.g. all JSON Object,
           //  all plain string/int/etc values, or even another JSON Array),
           //  and cannot have a name associated with them.

           // The easiest way to think about these two is that a JSON Object
           //  is like an RPG data structure, whereas a JSON Array is like
           //  an RPG data structure or normal field but with the Dim keyword
           //  used.

           // Because we can't name the values we're putting in our array, the
           //  second parm for RXS_ComposeJsonNumber() must be *OMIT.

           // We're using RXS_ComposeJsonNumber() to ensure that in the JSON
           //  the values we're passing show up as numeric (e.g. not wrapped
           //  in double quotes)

           // To handle large numbers effectively, RXS_ComposeJsonNumber()
           //  actually accepts a character representation of a number as
           //  opposed to an RPG numeric field type.
           RXS_ComposeJsonNumber( *Omit : %Char(i) : JsonArrayDS );
         endfor;

         // We're re-using the GenericArrayDS structure for the next few arrays
         //  as they are very simple arrays but the whole process is otherwise
         //  the same as for requiredCourseIds[]
         JsonArrayDS = RXS_ComposeJsonArray( 'courseIds' : RootDS );
         for i = 1 to 10;
           RXS_ComposeJsonNumber( *Omit : %Char(i * 2) : JsonArrayDS );
         endfor;

         JsonArrayDS = RXS_ComposeJsonArray( 'seriesIds' : RootDS );
         for i = 1 to 10;
           RXS_ComposeJsonNumber( *Omit : %Char(i * 3) : JsonArrayDS );
         endfor;

         JsonArrayDS = RXS_ComposeJsonArray( 'groupIds' : RootDS );
         for i = 1 to 10;
           RXS_ComposeJsonNumber( *Omit : %Char(i * 4) : JsonArrayDS );
         endfor;

         // Next, we need to add a date named datestamp to our RootDS.
         //  JSON doesn't have a 'date' data type, so we add this as a
         //  string and do whatever formatting the API we're calling requires.
         // In this case we're using a YYYY-MM-DD date format
         dateVal = %Char( %Date() : *ISO );
         RXS_ComposeJsonString( 'datestamp' : dateVal : RootDS );

         // Next we're going to add JSON boolean and null values
         RXS_ComposeJsonBoolean( 'processed' : RXS_JSON_TRUE : RootDS );
         RXS_ComposeJsonNull( 'referenceId' : RootDS );

         // Now that we've added all of the data fields to our JSON object,
         //  let's generate our JSON string
         JSON = RXS_GetJsonString( CreateJsonDS );

         // Dump JSON to file
         RXS_ResetDS( PutStmfDS : RXS_DS_TYPE_PUTSTMF );
         PutStmfDS.Stmf = '/tmp/json_excompose1.txt';
         RXS_PutStmf( JSON : PutStmfDS );

       on-error;
         RXS_DestroyJson( CreateJsonDS );
       endmon;

       // Always call RXS_DestroyJson() to free up the memory we used.
       // This must be called AFTER we retrieve our string
       //  with RXS_GetJsonString(), or there will be nothing to retrieve!
       // It is enough to just call RXS_DestroyJson() on the CreateJsonDS data
       //  structure - it will free the memory used by all of the child
       //  data structures that were linked to it as well.
       RXS_DestroyJson( CreateJsonDS );

       *INLR = *ON;
       return;
      /END-FREE