READ_JSON




le but du jeux étant de :

  1. A partir d'un web service produisant du JSON
    1. Définition


    2. Utilisation (exemple sous POSTMAN concurrent à SoapUI)



  2. Il faut le lire en RPG

Nos premiers tests vont utiliser la fonction HTTPGETCLOB de SYSTOOLS (le client REST par excellence)

Exécution


Temps d'exécution (mesuré par ANZCMDPFR)


Mais, pouvons nous, récupérer de la donnée utile (uniquement les valeurs) ?

SQL possède une fonction JSON_TABLE dans SYSTOOLS, permettant de retrouver une colonne à la fois

**free
// paramètre(s) en entrée
dcl-pi *n;
   unclient char(10);
END-PI;
// variables
dcl-s URL varchar(128) inz('http://localhost:10066/web/services/Clients/');
dcl-s wid int(10);
dcl-s wref char(10);
dcl-s wnom char(15);
dcl-s wprenom char(15);
dcl-s wdatechar char(10);
dcl-s wdatenaissance date;
dcl-s wadresse char(50);
dcl-s wsatut char(20);
URL += %trim(unclient); // += -> variable concaténée avec elle même
EXEC SQL
  select t1.value as id, t2.value as ref, t3.value as nom, t4.value as prenom,
         t5.value as datenaissance, t6.value as adresse, t7.value as statut
     into
         :wid, :wref, :wnom, :wprenom, :wdatechar, :wadresse, :wsatut
     from
         table (SYSTOOLS.JSON_TABLE(systools.json2bson(
         SYSTOOLS.HTTPGETCLOB(:URL, '')) , 'CLIENTRETOUR.ID' , 'i')
         ) as t1,
         table (SYSTOOLS.JSON_TABLE(systools.json2bson(
         SYSTOOLS.HTTPGETCLOB(:URL, '')) , 'CLIENTRETOUR.REFERENCE', 's:10')
         ) as t2,
         table (SYSTOOLS.JSON_TABLE(systools.json2bson(
         SYSTOOLS.HTTPGETCLOB(:URL, '')) , 'CLIENTRETOUR.NOM', 's:15')
         ) as t3,
         table (SYSTOOLS.JSON_TABLE(systools.json2bson(
         SYSTOOLS.HTTPGETCLOB(:URL, '')) , 'CLIENTRETOUR.PRENOM', 's:15')
         ) as t4,
         table (SYSTOOLS.JSON_TABLE(systools.json2bson(
         SYSTOOLS.HTTPGETCLOB(:URL, '')) , 'CLIENTRETOUR.DATENAISSANCE', 's:10')
         ) as t5,
         table (SYSTOOLS.JSON_TABLE(systools.json2bson(
         SYSTOOLS.HTTPGETCLOB(:URL, '')) , 'CLIENTRETOUR.ADRESSE', 's:50')
         ) as t6,
         table (SYSTOOLS.JSON_TABLE(systools.json2bson(
         SYSTOOLS.HTTPGETCLOB(:URL, '')) , 'CLIENTRETOUR.STATUT', 's:20')
         ) as t7;
 wdatenaissance = %date(wdatechar);

// pour voir
dsply (%char(wid) +'-' + wref);
dsply (%char(wdatenaissance));

*INLR = *on; 

Temps d'exécution (mesuré par ANZCMDPFR) Le web service est appelé 7 fois !

Et si nous utilisions YAJL? Le projet OpenSource porté sur IBM i, par Scott Klement.

**free
ctl-opt BNDDIR('YAJLLIB/YAJL');
/copy YAJLLIB/QRPGLESRC,YAJL_H

dcl-pi *n;
    unclient char(10);
END-PI;
dcl-s URL varchar(128) inz('http://localhost:10066/web/services/Clients/');
dcl-s resultat char(1024);
dcl-s errmsg   varchar(500);
dcl-s docNode  like(yajl_val);
dcl-s Node    like(yajl_val);
dcl-s val     like(yajl_val);
//
dcl-s wid int(10);
dcl-s wref char(10);
dcl-s wnom char(15);
dcl-s wprenom char(15);
dcl-s wdatenaissance date;
dcl-s wadresse char(50);
dcl-s wstatut char(20);
URL += %trim(unclient);

   EXEC SQL
         VALUES SYSTOOLS.HTTPGETCLOB(:URL , '') into :resultat;
 docnode = yajl_buf_load_tree(%addr(resultat):%len(%trimr(resultat)):errmsg);
 node =  YAJL_OBJECT_FIND(docNode: 'CLIENTRETOUR');
 val =   YAJL_OBJECT_FIND(node: 'ID');
 wid =   YAJL_GET_NUMBER(val);
 val =   YAJL_OBJECT_FIND(node: 'REFERENCE');
 wref =  YAJL_GET_STRING(val);
 val =   YAJL_OBJECT_FIND(node: 'NOM');
 wnom =  YAJL_GET_STRING(val);
 val =   YAJL_OBJECT_FIND(node: 'PRENOM');
 wprenom =  YAJL_GET_STRING(val);
 val =   YAJL_OBJECT_FIND(node: 'DATENAISSANCE');
 wdatenaissance =  %date(YAJL_GET_STRING(val));
 val =   YAJL_OBJECT_FIND(node: 'ADRESSE');
 wadresse =  YAJL_GET_STRING(val);
 val =   YAJL_OBJECT_FIND(node: 'STATUT');
 wstatut =  YAJL_GET_STRING(val);
 dsply (%char(wid) +'-' + wref);
 dsply (%char(wdatenaissance));

*INLR = *on; 

Temps d'exécution (mesuré par ANZCMDPFR)

Enfin, réalisons un dernier essai, directement basé sur les Api AXIS (voir l'article dans DeveloperWorks)

**free
ctl-opt BNDDIR('YAJLLIB/YAJL');
/copy YAJLLIB/QRPGLESRC,YAJL_H
// pour compiler CRTRPGMOD puis CRTPGM BNDSRVPGM((QSYSDIR/QAXIS10CC))
// ********************************************************************

dcl-pi *N;
  unclient char(10);
END-PI;
/COPY /QIBM/ProdData/OS/WebServices/V1/client/include/Axis.rpgleinc
DCL-S rc         INT(10);
DCL-S tHandle    POINTER;
DCL-S uri        CHAR(200);
DCL-S response   CHAR(32768);
DCL-S request    CHAR(32768);
DCL-S propBuf    CHAR(100);
dcl-s URL        varchar(128) inz('http://localhost:10066/web/services/Clients/');
dcl-s errmsg   varchar(500);
dcl-s docNode  like(yajl_val);
dcl-s Node     like(yajl_val);
dcl-s val      like(yajl_val);
//
dcl-s wid int(10);
dcl-s wref char(10);
dcl-s wnom char(15);
dcl-s wprenom char(15);
dcl-s wdatenaissance date;
dcl-s wadresse char(50);
dcl-s wstatut char(20);
URL += %trim(unclient);
// Create HTTP transport handle.
tHandle = axiscTransportCreate(url:AXISC_PROTOCOL_HTTP11);
if (tHandle = *NULL);
    DSPLY ('TransportCreate() failed');
    return;
endif;
// méthode GET
propBuf = 'GET' + X'00';
 axiscTransportSetProperty(tHandle: AXISC_PROPERTY_HTTP_METHOD: %addr(propBuf));

// Exécution, le résultat est placé dans "Response"
flushAndReceiveData();
 docnode = yajl_buf_load_tree(%addr(response):%len(%trimr(response)):errmsg); 
 node =  YAJL_OBJECT_FIND(docNode: 'CLIENTRETOUR');
 val =   YAJL_OBJECT_FIND(node: 'ID');
 wid =   YAJL_GET_NUMBER(val);
 val =   YAJL_OBJECT_FIND(node: 'REFERENCE');
 wref =  YAJL_GET_STRING(val);
 val =   YAJL_OBJECT_FIND(node: 'NOM');
 wnom =  YAJL_GET_STRING(val);
 val =   YAJL_OBJECT_FIND(node: 'PRENOM');
 wprenom =  YAJL_GET_STRING(val);
 val =   YAJL_OBJECT_FIND(node: 'DATENAISSANCE');
 wdatenaissance =  %date(YAJL_GET_STRING(val));
 val =   YAJL_OBJECT_FIND(node: 'ADRESSE');
 wadresse =  YAJL_GET_STRING(val);
 val =   YAJL_OBJECT_FIND(node: 'STATUT');
 wstatut =  YAJL_GET_STRING(val);
 dsply (%char(wid) +'-' + wref);
 dsply (%char(wdatenaissance));
// Cleanup handle.
 axiscTransportDestroy(tHandle);
*INLR=*ON;  
// =========================================
// Flush and Receive data
// =========================================
DCL-PROC flushAndReceiveData;
  dcl-pi *n;
  end-pi;
  DCL-S header     POINTER;
  dcl-s Header_data char(256) based(header);
  DCL-S property   CHAR(100);
  DCL-S bytesRead  INT(10) inz(0);
  clear response;
  clear header;
  // Flush data so request is sent
  rc = axiscTransportFlush(tHandle);
  if (rc = -1);
     DSPLY ('TransportFlush()');
     return;
  endif;
   // Receive data and print out data and response to stdout
   rc = axiscTransportReceive(tHandle: %ADDR(response): %SIZE(response): 0);
   if (rc = 0);
     DSPLY ('No data to read');
   else;
     dow rc > 0 AND bytesRead < %SIZE(response);
       bytesRead = bytesRead + rc;
       rc = axiscTransportReceive(tHandle:
       %ADDR(response)+bytesRead:
       %SIZE(response)-bytesRead:
       0);
     enddo;
  endif;
  if (rc > -1);
     rc = axiscTransportGetProperty(tHandle:
     AXISC_PROPERTY_HTTP_STATUS_CODE:
     %addr(header));
     DSPLY ('HTTP status code: ' + %subst(header_data:1:4));
  endif;
END-PROC;

Temps d'exécution (mesuré par ANZCMDPFR)




Suite à TR5 (7.2) / TR1 (7.3) testons la nouvelle version de JSON_TABLE (celle de QSYS2)

Avec HTTPGETCLOB

*free
dcl-pi *n; unclient char(10);
END-PI;

dcl-s URL varchar(128) inz('http://as400:10066/web/services/clients/');
dcl-s wid int(10);
dcl-s wref char(10); dcl-s wnom char(15);
dcl-s wprenom char(15); dcl-s wdatenaissance date;
dcl-s wadresse char(50);
dcl-s wstatut char(20);
URL += %trim(unclient);
EXEC SQL
    select * into :wid, :wref, :wnom, :wprenom,
         :wdatenaissance, :wadresse, :wstatut
     from JSON_TABLE(
       SYSTOOLS.HTTPGETCLOB(:URL, null),
         '$.client[*]'
       COLUMNS(
ID integer PATH '$.id', reference VARCHAR(25) PATH '$.reference', NOM VARCHAR(25) PATH '$.nom', prenom VARCHAR(25) PATH '$.prenom', naissance DATE PATH '$.datenaissance', adresse varchar(35) PATH '$.adresse', statut CHAR(12) PATH '$.statut' )) AS X;
 dsply (%char(wid) +'-' + wref);
 dsply (%char(wdatenaissance));
*INLR = *on;

Temps d'exécution (mesuré par ANZCMDPFR)

Avec les API Axis

**free
dcl-pi *n;
   unclient char(10);
END-PI;
/INCLUDE /QIBM/ProdData/OS/WebServices/V1/client/include/Axis.rpgleinc
DCL-S rc         INT(10);
DCL-S tHandle    POINTER;
DCL-S uri        CHAR(200);
DCL-S response   CHAR(32767);
DCL-S request    CHAR(32768);
DCL-S propBuf    CHAR(100);
dcl-s URL varchar(128) inz('http://as400:10066/web/services/clients/');
dcl-s json_data sqltype(Clob:32767) ;
dcl-s wid int(10);
dcl-s wref char(10);
dcl-s wnom char(15);
dcl-s wprenom char(15);
dcl-s wdatenaissance date;
dcl-s wadresse char(50);
dcl-s wstatut char(20);
URL += %trim(unclient);
// Create HTTP transport handle.
tHandle = axiscTransportCreate(url:AXISC_PROTOCOL_HTTP11);
if (tHandle = *NULL);
    DSPLY ('TransportCreate() failed');
    return;
endif;
// méthode GET
propBuf = 'GET' + X'00';
axiscTransportSetProperty(tHandle: AXISC_PROPERTY_HTTP_METHOD: %addr(propBuf));
// Exécution
flushAndReceiveData();
json_data_data = response;
json_data_len = %len(%trimr(response));
 EXEC SQL
     select * into :wid, :wref, :wnom, :wprenom,
             :wdatenaissance, :wadresse, :wstatut
          from JSON_TABLE(:json_data, '$.client[*]'
       COLUMNS( ID integer PATH '$.id',
         reference VARCHAR(25) PATH '$.reference',
         NOM VARCHAR(25) PATH '$.nom',
         prenom VARCHAR(25) PATH '$.prenom',
         naissance DATE PATH '$.datenaissance',
         adresse varchar(35) PATH '$.adresse',
         statut CHAR(12) PATH '$.statut'
      )) AS X;
 dsply (%char(wid) +'-' + wref);
 dsply (%char(wdatenaissance));
 // Cleanup handle.
 axiscTransportDestroy(tHandle);
*INLR=*ON;
       
// =========================================
// Flush and Receive data
// =========================================
DCL-PROC flushAndReceiveData;
    dcl-pi *n;
    end-pi;
 DCL-S header     POINTER;
 dcl-s Header_data char(256) based(header);
 DCL-S property   CHAR(100);
 DCL-S bytesRead  INT(10) inz(0);
 clear response;
 clear header;
 // Flush data so request is sent
    rc = axiscTransportFlush(tHandle);
    if (rc = -1);
         DSPLY ('TransportFlush()');
         return;
    endif;
 // Receive data and print out data and response to stdout
   rc = axiscTransportReceive(tHandle: %ADDR(response): %SIZE(response): 0);
   if (rc = 0);
         DSPLY ('No data to read');
   else;
     dow rc > 0 AND bytesRead < %SIZE(response);
         bytesRead = bytesRead + rc;
         rc = axiscTransportReceive(tHandle:
         %ADDR(response)+bytesRead:
         %SIZE(response)-bytesRead:
         0);
     enddo;
 endif;
 if (rc > -1);
    rc = axiscTransportGetProperty(tHandle:
         AXISC_PROPERTY_HTTP_STATUS_CODE:
         %addr(header));
    DSPLY ('HTTP status code: ' + %subst(header_data:1:4));
 endif;
END-PROC flushAndReceiveData; 

Temps d'exécution (mesuré par ANZCMDPFR)




©AF400