Return multiple records from an RPG to a REST consumer

Discussions relating to writing software in ILE RPG (RPG IV). This includes both fixed and free format RPG.
Post Reply
karldv22
Posts: 5
Joined: Mon Apr 04, 2022 1:55 pm
Location: Lloret de Mar (Spain)

Return multiple records from an RPG to a REST consumer

Post by karldv22 »

Hello everyone,
The first thing is to introduce myself, my name is Carlos, an RPG developer for many years from Barcelone, Spain.
I've been following Scott for a long time although I don't usually use these forums but today I'm launching my first post here.
THEME
Following Scott's information about publishing RPG programs for SOAP or REST consumption
1. I have set up an IWS server on the I-Series and have developed a small test program
2. Consumers (SOAPUI) work perfectly with a GET operation and achieving a single record.
THE CHALLENGE
I don't quite understand how to return a group of records through the *ENTRY PARM
I need to return a JSON (which is already transformed by IWS) but with multiple records.
I'm not able to do it.

Here, attached code of the RPG service and SoapUI Results as a file

Code: Select all

       //‚========================================================================
       //‚WSCUSTOMER
       //‚Webservice en RPG para exposición y uso
       //‚Carlos Del Valle
       //‚16/03/2022
       //‚========================================================================
       ctl-opt OPTION(*NODEBUGIO:*SRCSTMT) DFTACTGRP(*NO) THREAD(*SERIALIZE)
               ACTGRP('CDVREST') PGMINFO(*PCML: *MODULE);
       ctl-opt decedit('0,');
       //‚========================================================================
       //‚Database definition
       //‚========================================================================
       dcl-f COCLIN disk keyed usage(*INPUT) usropn ExtFile(file_coclin)
             prefix('CUST.');
       //‚========================================================================
       //‚General Definitions
       //‚========================================================================
       dcl-ds pgm_stat psds;
         sdsPgmID   char(10) pos(1);
         PgmID      char(10) pos(1);
         sdsWrkstn  char(10) pos(244);
         sdsJobUser char(10) pos(254);
         sdsCurUser char(10) pos(358);
         UsrId      char(10) pos(358);
         sdsJobnbr  char(6)  pos(264);
         sdsJobDate char(6) pos(270);
         sdsMsg     char(7)  pos(40);
         sdsMsgd    char(80) pos(91);
         sdsDate    char(8) pos(191);
       end-ds;

       dcl-ds err qualified;
       bytesProv int(10) inz(0);
       bytesAvail int(10) inz(0);
       end-ds;

       dcl-s MsgDta varchar(1000);
       dcl-s MsgKey char(4);

       dcl-s file_coclin char(21) inz('/COCLIN');
       dcl-s zxcias packed(3:0);
       dcl-s zxlist packed(1:0);

       //‚========================================================================
       //‚Back Error control
       //‚========================================================================
       dcl-pr QMHSNDPM ExtPgm;
         MessageID char(7) Const;
         QualMsgF char(20) Const;
         MsgData char(32767) Const options(*varsize);
         MsgDtaLen int(10) Const;
         MsgType char(10) Const;
         CallStkEnt char(10) Const;
         CallStkCnt int(10) Const;
         MessageKey char(4);
         ErrorCode char(32767) options(*varsize);
       end-pr;

       //‚========================================================================
       //‚Customer Record Estructure
       //‚========================================================================
         dcl-ds CUST ext qualified extname('COCLIN') end-ds;
       //‚========================================================================
       //‚*Entry Params
       //‚========================================================================
       dcl-pi *n;
         @ptran  char(25);                       // IN   Transacción
         @pcias  char(3);                        // IN   Compañía
         @pcust  like(Cust.s0cust);              // IN   Código Cliente (Not mandatory)
         @pCunm  like(Cust.s0des1);              // OUT  Nombre de Cliente
         @pVrno  like(Cust.s0nifi);              // OUT  Id Fiscal
         @pChai  like(Cust.s0grp2);              // OUT  Cadena Comercial
         @pPais  like(Cust.s0pais);              // OUT  Código de País
         @pZopa  like(Cust.s0zopa);              // OUT  Zona Comercial
         @pSupa  like(Cust.s0supa);              // OUT  SubZona Comercial
         @presu  char(3);                        // OUT  Resultado OK/NOK
         @pidms  char(10);                       // OUT  ID Mensaje
         @ptxms  char(150);                      // OUT  Texto Mensaje
       end-pi;
       //‚========================================================================
       //‚Program Structure
       //‚========================================================================
        file_coclin = 'PURLIBF' + @pcias + file_coclin;
        open(e) coclin;
           zxcias=%dec(@pcias:3:0);

           select;
             when @ptran='GetCust';
             exsr cs_GetCust;
             when @ptran='ListCust';
             exsr cs_ListCust;
           endsl;
       //‚========================================================================
       //‚End
       //‚========================================================================
        close(e) *all;
        *inLR = *on;
       //‚========================================================================
        begsr cs_GetCust;
       //‚========================================================================
           chain (zxcias:@pcust) coclin;
           if %found(coclin);
             exsr cs_MoveData;
             @presu='OK';
             @pidms=*Blanks;
             @ptxms=*blanks;
           else;
             @presu='NOK';
             @pidms='CPF9897';
             @ptxms='Customer not found.';
             //msgdta='Customer not found.';
             //QMHSNDPM( 'CPF9897' : 'QCPFMSG   *LIBL' : msgdta : %len(msgdta)
             //: '*ESCAPE' : '*PGMBDY' : 1 : MsgKey : err );
           endif;
        endsr;
       //‚========================================================================
        begsr cs_ListCust;
       //‚========================================================================
          zxlist=0;
          setll (zxcias) coclin;
          reade (zxcias) coclin;
          dow not %eof(coclin);
             zxlist=1;
             exsr cs_MoveData;
             @presu='OK';
             @pidms=*Blanks;
             @ptxms=*blanks;
          reade (zxcias) coclin;
          enddo;

          if zxlist=0;
            @presu='NOK';
            @pidms='CPF9897';
            @ptxms='Customer not found.';
            //msgdta='Customer not found.';
            //QMHSNDPM( 'CPF9897' : 'QCPFMSG   *LIBL' : msgdta : %len(msgdta)
            //: '*ESCAPE' : '*PGMBDY' : 1 : MsgKey : err );
          endif;
        endsr;
       //‚========================================================================
        begsr cs_MoveData;
       //‚========================================================================
          @pcust=Cust.s0cust;
          @pCunm=Cust.s0des1;
          @pVrno=Cust.s0nifi;
          @pChai=Cust.s0grp2;
          @pPais=Cust.s0pais;
          @pZopa=Cust.s0zopa;
          @pSupa=Cust.s0supa;
        endsr;
Attachments
soapui.png
soapui.png (78.98 KiB) Viewed 4098 times
jonboy49
Posts: 200
Joined: Wed Jul 28, 2021 8:18 pm

Re: Return multiple records from an RPG to a REST consumer

Post by jonboy49 »

This is the program PI for a simple test program I use in IWS presentations. (I used code tags in square brackets to format this - your code as you probably noticed is pretty much unreadable)

If you use the first approach I have shown here then you need to DE-SELECT the "Detect Length Fields" on the wizard's parameter page. When you do so the wizard display changes and you then have the opportunity to select the productList_count field as the controller for the number of output records.

Code: Select all

dcl-pi RestSrv4 ExtPgm;
   requestedCat        Like(catcod);
   result              char(20);
   productList_count   int(5);
   productList         LikeDS(product)  Dim(20);
end-pi;
There is an alternative approach that does use the "Detect" setting and in that case the PI looks like this.

Code: Select all

dcl-pi RestSrv5 ExtPgm;                      
  requestedCat        Like(catcod);          
  result              char(20);              
  productList         LikeDS(productList_T); 
end-pi;                                      

Dcl-ds  product ExtName('PRODUCT')  End-ds;  

Dcl-ds  productList_T  Qualified Template;   
  products_LENGTH  int(5);                   
  products         LikeDS(product)  Dim(20); 
End-Ds;                                      
Note that _LENGTH is the compulsory spelling and (for some weird reason) has to be in upper case. In my first example the name can be anything you choose. But if you choose to let IWS detect the length then it determines the spelling.

Using the first method the count is included in the generated JSON data. Using the second method no count is included.

If you want I can share with you a video of a presentation I did which uses these examples, but I don't want to publicly share this version so email me privately if you want to see it.

I hope this helps.
karldv22
Posts: 5
Joined: Mon Apr 04, 2022 1:55 pm
Location: Lloret de Mar (Spain)

Re: Return multiple records from an RPG to a REST consumer

Post by karldv22 »

Muchas Gracias !!!!!

It has run perfectly with the first approach.
Just a small problem to comment, I can't use Variable Dimension Array (RPG Limitation) and the JSON result is left with empty records once the content is processed.

I will study an alternative.

Saludos
Attachments
63HqymczWq.png
63HqymczWq.png (122.15 KiB) Viewed 4074 times
OG2b961HT5.png
OG2b961HT5.png (43.27 KiB) Viewed 4074 times
jonboy49
Posts: 200
Joined: Wed Jul 28, 2021 8:18 pm

Re: Return multiple records from an RPG to a REST consumer

Post by jonboy49 »

Just use a regularly defined RPG array and either of the answers I gave you when applied correctly will result in NO empty entries being output. Just make sure to set the value in the count field to the number of _active_ elements.

Look at the output of this: http://sidconf.idevcloud.com:10025/web/ ... ESTSRV5/02 the program allows for Dim(99) but only 5 were used. Change the number part to 01 and you'll see the change.

You just need to do what I showed you and the problem disappears.
jonboy49
Posts: 200
Joined: Wed Jul 28, 2021 8:18 pm

Re: Return multiple records from an RPG to a REST consumer

Post by jonboy49 »

P.S. You can use a varying length array as a parameter but you must set its length appropriately and define the PI/PR as the max. I describe how this works here: https://www.itjungle.com/2020/10/12/gur ... -and-more/
karldv22
Posts: 5
Joined: Mon Apr 04, 2022 1:55 pm
Location: Lloret de Mar (Spain)

Re: Return multiple records from an RPG to a REST consumer

Post by karldv22 »

Thanks a lot jonboy49,

I'll follow docs you linked me, and I'll do R+D, I'm working with this "in bursts" but When I'll have the final test working fine, i'll shared code and my humble conclusion in order to help everybody interested in this.
karldv22
Posts: 5
Joined: Mon Apr 04, 2022 1:55 pm
Location: Lloret de Mar (Spain)

Re: Return multiple records from an RPG to a REST consumer

Post by karldv22 »

Hi jonboy49,
I've been trying to send you a private e-mail such you offered me a video about this tophic, but i could not find your e-mail in your profile.
I would like go deep with this but really now i'm stuck and i've been trying differents RPG code but i've not still got good result.
Any help will be appreciated
Carlos
jonboy49
Posts: 200
Joined: Wed Jul 28, 2021 8:18 pm

Re: Return multiple records from an RPG to a REST consumer

Post by jonboy49 »

Sorry for the delay - I missed the posting of your request.

The video can be found here:

https://us02web.zoom.us/rec/play/3penvq ... 13yEo4xHTI

Let me know if you have any questions. Business email is jon dot paris at partner400 dot com. But if the question is of general interest please post it here.
karldv22
Posts: 5
Joined: Mon Apr 04, 2022 1:55 pm
Location: Lloret de Mar (Spain)

Re: Return multiple records from an RPG to a REST consumer

Post by karldv22 »

Thanks a lot jonboy49 !!!

With this amazing video I could to code my RPG program and following the API deployment details, I could to run it perfectly and cutting the empty JSON.

I hope this topic will help people that likes to implement this IWS

kind regards
Post Reply