RESTJSON

This example program demonstrates the basic structure of an RPG program utilizing RPG API Express to consume a REST based JSON web service via HTTP GET, and parse the JSON response.

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

/COPY QRPGLECPY,RXSCB

Dcl-Ds TransmitDS LikeDS(RXS_TransmitDS_t);
Dcl-Ds ParseJsonDS LikeDS(RXS_ParseJsonDS_t);
Dcl-Ds ErrorDS LikeDS(RXS_CatchThrowErrorDS_t);

Dcl-S JSON Like(RXS_Var64Kv_t);

Dcl-S gNameList Like(RXS_Var64Kv_t);
Dcl-S gCount Int(10);

// Please note that the REST web service being consumed by this example program
//   is not 100% available due to metering being performed on the
//   "demo" account. Usually you can make multiple attempts over time and
//   get a proper response eventually.

monitor;

  // Transmit

  RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT );
  TransmitDS.URI = 'http://api.geonames.org/citiesJSON'
                 + '?north=44.1&south=-9.9&east=-22.4'
                 + '&west=55.2&lang=de&username=demo';
  TransmitDS.LogFile = '/tmp/log.txt';
  TransmitDS.HTTPMethod = RXS_HTTP_METHOD_GET;
  JSON = RXS_Transmit( *Omit : TransmitDS );

  // Parse

  reset gCount;
  reset gNameList;
  RXS_ResetDS( ParseJsonDS : RXS_DS_TYPE_PARSEJSON );
  ParseJsonDS.Handler = %Paddr( JSONHandler );
  RXS_ParseJson( JSON : ParseJsonDS );

  // Output Parse Results as a Thrown Message

  RXS_ResetDS( ErrorDS : RXS_DS_TYPE_CATCHTHROWERROR );
  ErrorDS.MessageId = 'RXS9897';
  ErrorDS.MessageData = gNameList;
  ErrorDS.ThrowToCaller = RXS_YES;
  RXS_Throw( ErrorDS );


on-error;

  RXS_Joblog('Unexpected error occurred. See previous messages.');

endmon;

*INLR = *ON;
return;

Dcl-Proc JSONHandler;
  Dcl-Pi *N Ind;
    pType Int(5) Const;
    pPath Like(RXS_Var64Kv_t) Const;
    pIndex Uns(10) Const;
    pData Pointer Const;
    pDataLen Uns(10) Const;
  End-Pi;

  select;

    when pType = RXS_JSON_OBJECT_END
     and pPath = '/geonames[*]';
      gNameList += ', ';

    when pType = RXS_JSON_OBJECT_END
     and pPath = '/';
      if gCount > 0;
        gNameList += 'No more names!';
      endif;

    when pType = RXS_JSON_STRING
     and pPath = '/geonames[*]/toponymName';
      gCount += 1;
      gNameList += %Char(gCount) + ': ';
      gNameList += RXS_STR( pData : pDataLen );

    // If the service is unavailable to the usage metering mentioned earlier,
    //   there will be JSON data available for parsing per the below

    when pPath = '/status/message';
      gNameList = RXS_STR( pData : pDataLen );

    when pPath = '/status/value';
      gNameList += ' (' + RXS_STR( pData : pDataLen ) + ')';

  endsl;

  // If you want to stop parsing early for whatever reason, return
  // RXS_JSON_STOP_PARSING

  return RXS_JSON_CONTINUE_PARSING;
End-Proc;
 
     H DFTACTGRP(*NO) ACTGRP(*CALLER) BNDDIR('RXSBND') OPTION(*NODEBUGIO)
     H EXTBININT(*YES) DECEDIT('0.')
     H TEXT('Fixed Format Ex - RESTJSON')

      /COPY QRPGLECPY,RXSCB

     D JSONHandler     PR              N
     D  pType                         5I 0 Const
     D  pPath                              Const Like(RXS_Var64Kv_t)
     D  pIndex                       10U 0 Const
     D  pData                          *   Const
     D  pDataLen                     10U 0 Const

     D TransmitDS      DS                  LikeDS(RXS_TransmitDS_t)
     D ParseJsonDS     DS                  LikeDS(RXS_ParseJsonDS_t)
     D ErrorDS         DS                  LikeDS(RXS_CatchThrowErrorDS_t)

     D JSON            S                   Like(RXS_Var64Kv_t)

     D gNameList       S                   Like(RXS_Var64Kv_t)
     D gCount          S             10I 0

      /FREE

       // Please note that the REST web service being consumed by this example program
       //   is not 100% available due to metering being performed on the
       //   "demo" account. Usually you can make multiple attempts over time and
       //   get a proper response eventually.

       monitor;

         // Transmit

         RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT );
         TransmitDS.URI = 'http://api.geonames.org/citiesJSON'
                        + '?north=44.1&south=-9.9&east=-22.4'
                        + '&west=55.2&lang=de&username=demo';
         TransmitDS.LogFile = '/tmp/log.txt';
         TransmitDS.HTTPMethod = RXS_HTTP_METHOD_GET;
         JSON = RXS_Transmit( *Omit : TransmitDS );

         // Parse

         reset gCount;
         reset gNameList;
         RXS_ResetDS( ParseJsonDS : RXS_DS_TYPE_PARSEJSON );
         ParseJsonDS.Handler = %Paddr( JSONHandler );
         RXS_ParseJson( JSON : ParseJsonDS );

         // Output Parse Results as a Thrown Message

         RXS_ResetDS( ErrorDS : RXS_DS_TYPE_CATCHTHROWERROR );
         ErrorDS.MessageId = 'RXS9897';
         ErrorDS.MessageData = gNameList;
         ErrorDS.ThrowToCaller = RXS_YES;
         RXS_Throw( ErrorDS );

       on-error;

         RXS_Joblog('Unexpected error occurred. See previous messages.');

       endmon;

       *INLR = *ON;
       return;

      /END-FREE

     P JSONHandler     B                   Export
     D                 PI              N
     D  pType                         5I 0 Const
     D  pPath                              Const Like(RXS_Var64Kv_t)
     D  pIndex                       10U 0 Const
     D  pData                          *   Const
     D  pDataLen                     10U 0 Const
      /FREE

       select;

         when pType = RXS_JSON_OBJECT_END
          and pPath = '/geonames[*]';
           gNameList += ', ';

         when pType = RXS_JSON_OBJECT_END
          and pPath = '/';
           if gCount > 0;
             gNameList += 'No more names!';
           endif;

         when pType = RXS_JSON_STRING
          and pPath = '/geonames[*]/toponymName';
           gCount += 1;
           gNameList += %Char(gCount) + ': ';
           gNameList += RXS_STR( pData : pDataLen );

         // If the service is unavailable to the usage metering mentioned earlier,
         //   there will be JSON data available for parsing per the below

         when pPath = '/status/message';
           gNameList = RXS_STR( pData : pDataLen );

         when pPath = '/status/value';
           gNameList += ' (' + RXS_STR( pData : pDataLen ) + ')';

       endsl;

       // If you want to stop parsing early for whatever reason, return
       // RXS_JSON_STOP_PARSING

       return RXS_JSON_CONTINUE_PARSING;

      /END-FREE
     P                 E